WAL Programmer Manual

0.8.2

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?)

(** base exponent) ↦ (int?)
     base : (int?)
 exponent : (int?)
Examples
>-> (+ 1 2 3 4)
10
>-> (/ 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 the last expression 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
  
(define id expr)
       id : (symbol?)
     expr : WAL expression    
Evaluates expr and binds the result to id and returns the result.
Examples
>-> (define x 10)
10
>-> x
10
>-> (define y (+ x x))
20
(set! id expr)
       id : (symbol?)
     expr : WAL expression    
Updates the existing binding id to the result of evaluating expr and returns the result.
Examples
>-> (define x 10)
10
>-> x
10
>-> (set! x (+ x x))
20
>-> x
20

Functions

(defun name (args+) body+)
     name : (symbol?)
     args : (symbol?) or ((symbol?)+)
     body : WAL expressions
  
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 functions' parameters can be specified. The parameters can either be a list of symbols, or a single symbol. If it is a list of symbols, the function expects one argument for each entry. If a function is called, the arguments to the function are evaluated and bound to the symbols in the argument list args. Then, the body
Formatting Style
Typically, the argument list is enclosed in [] braces for better readability.
Example
>-> (defun times-two [n] (* n 2))
Function: times-two
Args: (n)
(do times-two (* n 2))
>-> (times-two 5)
10
If it is a single symbol, all arguments to the function are passed to the function as a list which is bound to the symbol. In this case, the function can accept a variable number of arguments. All following arguments define the expressions of the function body.
Example
>-> (defun times-two-list xs (for/list [x xs] (* x 2)))
Function: times-two-list
Args: xs
(do "times-two-list" (map (lambda (x) (* x 2)) xs))
>-> (times-two-list 1 2 3)
(2 4 6)
  (fn (args+) body+)
       name : (symbol?)
       args : (symbol?) or ((symbol?)+)
       body : WAL expressions
    
Anonymous functions can be created using the fn function.
Example
>-> ((fn [a b] (+ a b)) 1 2)
3
WAL has closures, thus functions can capture variables.
(defun make-counter [name]
  (define cnt 0)
  (fn [] (set! cnt (+ cnt 1))
         (print name ": " cnt)))

(define cnt1 (make-counter "Cnt1"))
(define cnt2 (make-counter "Cnt2"))
(cnt1)
(cnt1)
(cnt2)
(cnt1)
Running this program produces following output.
Cnt1: 1
Cnt1: 2
Cnt2: 1
Cnt1: 3

Control Flow

(do body+)
     body : WAL expression
  
Evaluates the expressions in body in order and returns the result of the last element in body. Useful to wrap evaluate multiple expressions in places where only one expression is allowed (e.g., in if expressions).
(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 truthy result (i.e., 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 a falsy result (i.e., 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. Both then and else can only be single expressions. However, if multiple expressions are required they can be wrapped in do blocks like shown in the following example.
Example:
(if a[2]
  (do (print "Option a")
      (set! a (list))
  (do (print "Option b")
      (set! a (list))))
(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 using 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 always match) 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 case, evaluates the corresponding expressions returning the last result. A default value that is returned if no other clause matches can be specified by using default as the value.
Example
(case (+ a b)
      [1 "one"]
      [2 "two"]
      [3 "three"]
      [default "> three"])

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

(eval-file file)
     module : (symbol?)    
With eval-file, 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 file can overwrite definitions made in the running program.
(exit code)
      code : (int?)    
Exits with code as the return value.