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.
(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.