WAL Programmer Manual

0.6.2a

1. Core Language

This section documents the core functionality of WAL including arithmetic, control flow, and data structures.

Arithmetic

(+ expr*) ↦ (int?)
(- expr*) ↦ (int?)
(* expr*) ↦ (int?)
     expr : (int?)
    
(/ a b) ↦ (int?)
(fdiv a b)  ↦ Real
        a : (int?)
        b : (int?)

(** base exponent) ↦ (int?)
     base : (int?)
 exponent : (int?)
All arithmetic functions except fdiv return rounded results of type (int?). fdiv is a floating point division that returns unrounded real numbers.
Examples
>-> (+ 1 2 3 4)
10
>-> (/ 10 3)
3
>-> (fdiv 10 3)
3.3333333333333335
  

Logic and Comparisons

(! expr) ↦ (int?)
(&& expr*) ↦ (int?)
(|| expr*) ↦ (int?)
     expr : (int?), (list?), (array?)
(= expr*) ↦ (int?)
(!= expr*) ↦ (int?)

(> a b) ↦ (int?)
(< a b) ↦ (int?)
(>= a b) ↦ (int?)
(<= a b) ↦ (int?)   
        a : (int?)
        b : (int?)
Many logical functions such as the logical and && support more than two inputs. In the case of && all arguments must be positive. 1 and 0 are equivalent to the boolean literals #t and #f.
Examples
>-> (! #f)
#t
>-> (&& #t #t)
#t
>-> (&& #t #t #f)
#f
>-> (&& #t #t #0)
#f	
>-> (= 5 5)
#t
>-> (= '(1 2) '(1 2))
#t	
  

Program State

(let (id expr)+ body)
       id : (symbol?)
     expr : WAL expression
     body : WAL expression
  
The let function locally binds the results of the expressions expr to the symbols id during the evaluation of body. The result of the function is the result of the evaluation of body. Expressions are evaluated in the order they are passed to the function and later bindings can use earlier bindings.
Examples
>-> (let [x 10]
          x)	
10
>-> (let [x 10]
         [y 12]	
         (+ x y))	
22
>-> (let [x 10]
         [y x]	
         (+ x y))	
20
  
(set (id expr)+)
       id : (symbol?)
     expr : WAL expression    
  
Evaluates all expressions expr in the order they are passed to the function and sets the corresponding variable id to the result of this evaluation. If the function is evaluated inside a local scope the update is performed in this scope, otherwise the global scope is used.

Functions

(defun name (args+) body+)
     name : (symbol?)
     args : (symbol?), ((symbol?) (symbol?))
     body : WAL expression
  
New functions can be defined using the defun function. The first argument to defun is the name to which the new function definition is bound. Following the name the list of arguments must be specified. Finally, the expressions of the function body.
Formatting Style
Typically, the argument list is enclosed in [] braces for better readability.
If a function is called, the arguments to the function are evaluated and bound to the ids in the argument list args. Then, the body expressions expressions are evaluated and the result of the last expression is returned.
Example
(defun times-two [n]
  (* n 2))

Capturing Variables from the Calling Scope

Nested function calls dont inherit the surrounding scope and are evaluated inside a new and empty scope. If the function wants to access variables from the calling scope they must be captured by the function. To capture a variable a tuple (a b) can be included in the functions argument list. For each tuple like this, b is evaluated in the calling scope and bound to a in the scope of the called function. After the function is evaluated a is copied from the called to the calling scope, overwriting any previous binding to the same name.
Example
In this example we define a function calling which sets the variable x to the value 5. We then call the function called1 which tries to print the value of x. Since x is not contained in the new scope of called1 the default value of 0 is returned (in WAL evaluating undefined variables returns 0). In comparison the call to called2 binds the variable x from the scope of calling to the variable x in the scope of called2. Thus, evaluating x in called2 returns the value 5.
(defun calling []
  (set [x 5])
  (called1)
  (called2))

(defun called1 []
  (print "Called1 " x))

(defun called2 [(x x)]
  (print "Called2 " x))
If we evaluate the function calling we get the following output printed.
>-> (calling)
Called1 0
Called2 5

Control Flow

(when cond body+)
     cond : WAL expression
     body : WAL expression
  
Evaluates the expressions in body in order and returns the result of the last element in body if cond evaluates to a positive result (e.g. int > 0, #t, or a non empty list). Otherwise returns None.
(unless cond body+)
     cond : WAL expression
     body : WAL expression
  
Evaluates the expressions in body in order and returns the result of the last element in body if cond evaluates to 0, #f, or the empty list. Otherwise returns None.
(if cond then else)
     cond : WAL expression
     then : WAL expression
     else : WAL expression
  
Evaluates then and returns the result if cond evaluates to to a positive result (e.g. int > 0, #t, or a non empty list) otherwise evaluates else and returns the result.
(cond (guard expr+)+)
    guard : WAL expression
     expr : WAL expression
  
The cond function implements a condition with multiple cases. It is a more elegant and flexible way than multiple nested if's. It goes through all clauses and evaluates the exprs for the first clause for which guard evaluates to a positive result. Returns the evaluated result of the last expression of the chosen clause.
Example
The example below showcases uses cond in a recursive function implementing the Fibonacci sequence. If the argument n is either 1 or 2 the result of the function is 1 otherwise the last default case (clauses with #t are always evaluated) is evaluated which recursively calls fib.
(defun fib [n]
  (cond [(= n 1) 1]
        [(= n 2) 1]
        [#t (+ (fib (- n 1))
               (fib (- n 2)))]))
(case key (value expr+)+)
      key : WAL expression    
    value : WAL expression
     expr : WAL expression
  
The case function implements a condition with multiple cases. It goes through all clauses, checks if value is equal to the evaluated key, and, if this is the cse, evaluates the corresponding expressions returning the last result.
Example
The example below showcases uses cond in a recursive function implementing the Fibonacci sequence. If the argument n is either 1 or 2 the result of the function is 1 otherwise the last default case (clauses with #t are always evaluated) is evaluated which recursively calls fib.
(defun fib [n]
  (cond [(= n 1) 1]
        [(= n 2) 1]
        [#t (+ (fib (- n 1))
               (fib (- n 2)))]))

Printing

(print args*)
      args : WAL expression
  
Evaluates args in the order they are passed, prints them to the standart output, and append a newline.
(printf format args*)
    format : (string?)    
      args : WAL expression
  
C-style printf function. Evaluates args in the order they are passed and prints them to the standart output in a format specified by format. The formatting string follows the Python printf-style formatting rules.

Utility

(require module)
     module : (symbol?)    
  
With the require function WAL code in other files can be made availabe in the executed file. Evaluates the WAL code in module + .wal and combines the resulting program state with the current program state of the running program. This means, that definitions inside module can overwrite definitions made in the running program.
(exit code)
      code : (int?)    
  
Exits with return code.