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 patterns.
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 ofPV)Vmatches the patternP. Any variables bound inPare 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-matchis required. For example it can be used as the first clause of anifexpression, in which case the scope of the variables bound in thepatternincludes 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
ifexpression is evaluated as follows: first, thetest-or-matchis evaluated. If it it true, thenconsequentis evaluated and its values are returned. Otherwisealternateis evaluated and its values are returned. Iftestyields#fand noalternateis 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
consequentandalternateexpressions are in tail context if theifexpression itself is.
Syntax: cond cond-clause +
Syntax: cond cond-clause * (else expression...)
cond-clause::=(test-or-matchbody)
|(test=>expression)
A
condexpression is evaluated by evaluating thetest-or-matchs of successivecond-clauses in order until one of them evaluates to a true value. When atest-or-matchis true value, then the remainingexpressions in itscond-clauseare evaluated in order, and the results of the lastexpressionin thecond-clauseare returned as the results of the entirecondexpression. Variables bound by thetest-or-matchare visible inbody. If the selectedcond-clausecontains only thetest-or-matchand noexpressions, then the value of the lasttest-expressionis returned as the result. If the selectedcond-clauseuses the=>alternate form, then theexpressionis evaluated. Its value must be a procedure. This procedure should accept one argument; it is called on the value of thetest-expressionand the values returned by this procedure are returned by thecondexpression.If all
test-or-matchs evaluate to#f, and there is noelseclause, then the conditional expression returns unspecified values; if there is anelseclause, then itsexpressions 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-clauseof one of the following forms:(testexpression*) (elseexpressionexpression*)the last
expressionis in tail context if thecondform itself is. For acond clauseof the form:(test=>expression)the (implied) call to the procedure that results from the evaluation of
expressionis in tail context if thecondform 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::=(elseexpression+)
|(else =>expression)
Each
datumis an external representation of some object. Eachdatumin the entirecaseexpression should be distinct.A
caseexpression is evaluated as follows.
The
case-keyis evaluated and its result is compared usingeqv?against the data represented by thedatums of eachcase-clausein turn, proceeding in order from left to right through the set of clauses.If the result of evaluating
case-keyis equivalent to a datum of acase-clause, the correspondingexpressions are evaluated from left to right and the results of the last expression in thecase-clauseare returned as the results of thecaseexpression. Otherwise, the comparison process continues.If the result of evaluating
keyis different from every datum in each set, then if there is ancase-else-clauseits expressions are evaluated and the results of the last are the results of thecaseexpression; otherwise the result ofcaseexpression is unspecified.If the selected
case-clauseorcase-else-clauseuses the=>alternate form, then theexpressionis evaluated. It is an error if its value is not a procedure accepting one argument. This procedure is then called on the value of thekeyand the values returned by this procedure are returned by thecaseexpression.(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
expressionof acase clauseis in tail context if thecaseexpression itself is.
Syntax: match match-key match-clause +
The
matchform is a generalization ofcaseusingpatterns,
match-key::=expression
match-clause::=
(pattern[guard]body)
The
match-keyis evaluated, Then thematch-clauses are tried in order. The firstmatch-clausewhosepatternmatches (and theguard, if any, is true), is selected, and the correspondingbodyevaluated. It is an error if nomatch-clausematches.(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
casefeature 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-matchforms,#tis returned.If the
andis not intest-or-matchcontext, then the last sub-expression (if any) must be atest-expression, and not a ‘?’ form. In this case thetest-or-matchexpressions are evaluated from left to right until either one of them is false (atest-expressionis false or a ‘?’ match fails), or the lasttest-expressionis reached. In the former case, theandexpression returns#fwithout evaluating the remaining expressions. In the latter case, the last expression is evaluated and its values are returned.If the
andis intest-or-matchcontext, then the last sub-form can be ‘?’ form. They are evaluated in order: If one of them is false, the entireandis false; otherwise theandis true.Regardless, any bindings made by earlier ‘
?’ forms are visible in latertest-or-matchforms.(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
andkeyword could be defined in terms ofifusingsyntax-rulesas follows:(define-syntax and (syntax-rules () ((and) #t) ((and test) test) ((and test1 test2 ...) (if test1 (and test2 ...) #t))))The last
test-expressionis in tail context if theandexpression itself is.
Syntax: or test-expression ...
If there are no
test-expressions,#fis returned. Otherwise, thetest-expressions are evaluated from left to right until atest-expressionreturns a true valuevalor the lasttest-expressionis reached. In the former case, theorexpression returnsvalwithout 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
orkeyword could be defined in terms ofifusingsyntax-rulesas 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-expressionis in tail context if theorexpression itself is.
Procedure: not test-expression
The
notprocedure returns#tiftest-expressionis false, and returns#fotherwise.(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-expressionis true, evaluate eachformin order, returning the value of the last one.
Syntax: unless test-expression form...
If
test-expressionis false, evaluate eachformin order, returning the value of the last one.