Kawa Scheme has the usual conditional expression forms,
such as if
, case
, and
, and or
:
(if (> 3 2) 'yes 'no) ⇒ yes
Kawa also allows you bind variables in the condition,
using the ‘?
’ operator.
(if (and (? x ::integer (get-value)) (> x 0)) (* x 10) 'invalid)
In the above, if (get-value)
evaluates to an integer, that
integer is bound to the variable x
, which is visible
in both following sub-expression of and
,
as well case the true-part of the if
.
Specifically, the first sub-expression of an if
is a test-or-match
, which can be a test-expression
,
or a ‘?
’ match expression, or a combination using and
:
test-or-match
::=
test-expression
| (?
pattern
expression
)
| (and
test-or-match
*)
A test-or-match
is true if every nested test-expression
is true, and every ‘?
’ operation succeeds.
It produces a set of variable bindings which is the union
of the bindings produced by all the pattern
s.
In an and
form, bindings produced by a pattern
are visible to
all subsequent test-or-match
sub-expressions.
Syntax: ?
pattern
expression
The form
(?
informally is true if the value ofP
V
)V
matches the patternP
. Any variables bound inP
are in scope in the “true” path of the containing conditional.This has the form of an expression, but it can only be used in places where a
test-or-match
is required. For example it can be used as the first clause of anif
expression, in which case the scope of the variables bound in thepattern
includes the second (consequent
) sub-expression. On the other hand, a ‘?
’ form may not be used as an argument to a procedure application.
Syntax: if
test-or-match
consequent
alternate
Syntax: if
test-or-match
consequent
consequent
::=
expression
alternate
::=
expression
An
if
expression is evaluated as follows: first, thetest-or-match
is evaluated. If it it true, thenconsequent
is evaluated and its values are returned. Otherwisealternate
is evaluated and its values are returned. Iftest
yields#f
and noalternate
is specified, then the result of the expression is void.(if (> 2 3) 'yes 'no) ⇒ no (if (> 3 2) (- 3 2) (+ 3 2)) ⇒ 1 (if #f #f) ⇒ #!void (if (? x::integer 3) (+ x 1) 'invalid) ⇒ 4 (if (? x::integer 3.4) (+ x 1) 'invalid) ⇒ 'invalidThe
consequent
andalternate
expressions are in tail context if theif
expression itself is.
Syntax: cond
cond-clause
+
Syntax: cond
cond-clause
*
(else
expression
…
)
cond-clause
::=
(
test-or-match
body
)
|(
test
=>
expression
)
A
cond
expression is evaluated by evaluating thetest-or-match
s of successivecond-clause
s in order until one of them evaluates to a true value. When atest-or-match
is true value, then the remainingexpression
s in itscond-clause
are evaluated in order, and the results of the lastexpression
in thecond-clause
are returned as the results of the entirecond
expression. Variables bound by thetest-or-match
are visible inbody
. If the selectedcond-clause
contains only thetest-or-match
and noexpression
s, then the value of the lasttest-expression
is returned as the result. If the selectedcond-clause
uses the=>
alternate form, then theexpression
is evaluated. Its value must be a procedure. This procedure should accept one argument; it is called on the value of thetest-expression
and the values returned by this procedure are returned by thecond
expression.If all
test-or-match
s evaluate to#f
, and there is noelse
clause, then the conditional expression returns unspecified values; if there is anelse
clause, then itsexpression
s are evaluated, and the values of the last one are returned.(cond ((> 3 2) 'greater) ((< 3 2) 'less)) ⇒ greater (cond ((> 3 3) 'greater) ((< 3 3) 'less) (else 'equal)) ⇒ equal (cond ('(1 2 3) => cadr) (else #f)) ⇒ 2For a
cond-clause
of one of the following forms:(test
expression
*) (elseexpression
expression
*)the last
expression
is in tail context if thecond
form itself is. For acond clause
of the form:(test
=>expression
)the (implied) call to the procedure that results from the evaluation of
expression
is in tail context if thecond
form itself is.
Syntax: case
case-key
case-clause
+
Syntax: case
case-key
case-clause
*
case-else-clause
case-key
::=
expression
case-clause
::=
((
datum
*)
expression
+)
|((
datum
*)
=>
expression
)
case-else-clause
::=
(else
expression
+)
|(else =>
expression
)
Each
datum
is an external representation of some object. Eachdatum
in the entirecase
expression should be distinct.A
case
expression is evaluated as follows.
The
case-key
is evaluated and its result is compared usingeqv?
against the data represented by thedatum
s of eachcase-clause
in turn, proceeding in order from left to right through the set of clauses.If the result of evaluating
case-key
is equivalent to a datum of acase-clause
, the correspondingexpression
s are evaluated from left to right and the results of the last expression in thecase-clause
are returned as the results of thecase
expression. Otherwise, the comparison process continues.If the result of evaluating
key
is different from every datum in each set, then if there is ancase-else-clause
its expressions are evaluated and the results of the last are the results of thecase
expression; otherwise the result ofcase
expression is unspecified.If the selected
case-clause
orcase-else-clause
uses the=>
alternate form, then theexpression
is evaluated. It is an error if its value is not a procedure accepting one argument. This procedure is then called on the value of thekey
and the values returned by this procedure are returned by thecase
expression.(case (* 2 3) ((2 3 5 7) 'prime) ((1 4 6 8 9) 'composite)) ⇒ composite (case (car '(c d)) ((a) 'a) ((b) 'b)) ⇒ unspecified (case (car '(c d)) ((a e i o u) 'vowel) ((w y) 'semivowel) (else => (lambda (x) x))) ⇒ cThe last
expression
of acase clause
is in tail context if thecase
expression itself is.
Syntax: match
match-key
match-clause
+
The
match
form is a generalization ofcase
usingpattern
s,
match-key
::=
expression
match-clause
::=
(
pattern
[guard
]body
)
The
match-key
is evaluated, Then thematch-clause
s are tried in order. The firstmatch-clause
whosepattern
matches (and theguard
, if any, is true), is selected, and the correspondingbody
evaluated. It is an error if nomatch-clause
matches.(match value (0 (found-zero)) (x #!if (> x 0) (found-positive x)) (x #!if (< x 0) (found-negative x)) (x::symbol (found-symbol x)) (_ (found-other)))One
case
feature is not (yet) directly supported bymatch
: Matching against a list of values. However, this is easy to simulate using a guard usingmemq
,memv
, ormember
:;; compare similar example under case (match (car '(c d)) (x #!if (memv x '(a e i o u)) ’vowel) (x #!if (memv x '(w y)) ’semivowel) (x x))
Syntax: and
test-or-match
*
If there are no
test-or-match
forms,#t
is returned.If the
and
is not intest-or-match
context, then the last sub-expression (if any) must be atest-expression
, and not a ‘?
’ form. In this case thetest-or-match
expressions are evaluated from left to right until either one of them is false (atest-expression
is false or a ‘?
’ match fails), or the lasttest-expression
is reached. In the former case, theand
expression returns#f
without evaluating the remaining expressions. In the latter case, the last expression is evaluated and its values are returned.If the
and
is intest-or-match
context, then the last sub-form can be ‘?
’ form. They are evaluated in order: If one of them is false, the entireand
is false; otherwise theand
is true.Regardless, any bindings made by earlier ‘
?
’ forms are visible in latertest-or-match
forms.(and (= 2 2) (> 2 1)) ⇒ #t (and (= 2 2) (< 2 1)) ⇒ #f (and 1 2 'c '(f g)) ⇒ (f g) (and) ⇒ #t (and (? x ::int 23) (> x 0)) ⇒ #tThe
and
keyword could be defined in terms ofif
usingsyntax-rules
as follows:(define-syntax and (syntax-rules () ((and) #t) ((and test) test) ((and test1 test2 ...) (if test1 (and test2 ...) #t))))The last
test-expression
is in tail context if theand
expression itself is.
Syntax: or
test-expression
…
If there are no
test-expression
s,#f
is returned. Otherwise, thetest-expression
s are evaluated from left to right until atest-expression
returns a true valueval
or the lasttest-expression
is reached. In the former case, theor
expression returnsval
without evaluating the remaining expressions. In the latter case, the last expression is evaluated and its values are returned.(or (= 2 2) (> 2 1)) ⇒ #t (or (= 2 2) (< 2 1)) ⇒ #t (or #f #f #f) ⇒ #f (or '(b c) (/ 3 0)) ⇒ (b c)The
or
keyword could be defined in terms ofif
usingsyntax-rules
as follows:(define-syntax or (syntax-rules () ((or) #f) ((or test) test) ((or test1 test2 ...) (let ((x test1)) (if x x (or test2 ...))))))The last
test-expression
is in tail context if theor
expression itself is.
Procedure: not
test-expression
The
not
procedure returns#t
iftest-expression
is false, and returns#f
otherwise.(not #t) ⇒ #f (not 3) ⇒ #f (not (list 3)) ⇒ #f (not #f) ⇒ #t (not ’()) ⇒ #f (not (list)) ⇒ #f (not ’nil) ⇒ #f (not #!null) ⇒ #t
Syntax: when
test-expression
form...
If
test-expression
is true, evaluate eachform
in order, returning the value of the last one.
Syntax: unless
test-expression
form...
If
test-expression
is false, evaluate eachform
in order, returning the value of the last one.