Control flow
The language contains multiple special forms for managing control flow.
Do
You can evaluate multiple expressions together using do
:
> (do (print "Number: ") (+ 1 2))
Number: 3
The value of the whole expression is the value of the last expression.
If
Conditional evaluation is accomplished with the if
expression which is of the form (if test consequent alternate)
. If test evaluates to truthy value, consequent is evaluated and returned. If test evaluates to falsy value, alternate is evaluated and returned:
> (if (< 1 2) "yes" "no")
"yes"
If alternate is not provided, null is returned in its place:
> (if (str? 1) "string")
null
And, or
The and
form returns the first expression that evaluates to falsy value:
> (and 2 true "str" 0 3)
0
The or
form returns the first expression that evaluates to truthy value:
> (or 0 false 3 5)
3
Without arguments and
and or
return true and false respectively:
> (and)
true
> (or)
false
Cond, case and case-strict
When you have more than two possible paths of execution, it is convenient to use the cond
and case
forms.
Consider the following defined for these examples:
> (def n 4)
4
For cond
, the first item of each argument is evaluated. If it evaluates to truthy value, the following expression is evaluated and returned:
> (cond ((= n 2) "two") ((= n 4) "four") ((= n 6) "six"))
"four"
For case
, the first argument is evaluated, and then it is matched against the first item of the remaining arguments. If there is a match, the following expression is evaluated and returned:
> (case (% n 2) (0 "even") (1 "odd"))
"even"
Note that the values to match against, 0
and 1
in the above example, are not evaluated.
The case-strict
is similar, but uses strict comparison:
> (case n ("4" "string") (4 "integer"))
"string"
> (case-strict n ("4" "string") (4 "integer"))
"integer"
Both cond
and case
can have an else
form which is matched if nothing else matched up to that point:
> (cond ((< n 2) "small") (else "big"))
"big"
> (case (% n 2) (1 "odd") (else "even"))
"even"
Both cond
and case
can have more than one expression which is evaluated after a successful match:
> (cond ((int? n) (print "Number: ") n))
Number: 4
The arguments to cond
and case
can be also be given as vectors:
> (cond [(int? n) "integer"] [else "other"])
"integer"
If no match is found, and else
is not defined, cond
and case
return null.
While
Looping is accomplished with the while
expression which is of the form (while test expr1 expr2 ...)
. The test is evaluated at the beginning of each iteration and if it returns truthy value, the remaining expressions are evaluated. The value of the whole expression is the value of the last evaluated sub-expression.
> (let (i 5) (while (> i 0) (print i) (def i (dec i))))
543210
Although the above example illustrates how to use while
, this type of code is discouraged. Generally it is recommended to use recursion instead of iteration in these type of scenarios. Usually it results in cleaner code as well. The while
expression is better suited for something like the main loop of a program.