Next: Variables and Patterns, Previous: Boolean values, Up: Program structure [Contents][Index]
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.
The form (? P V)
informally
is true if the value of V matches the pattern P.
Any variables bound in P 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 an
if
expression, in which case the scope of the variables bound in
the pattern
includes the second (consequent) sub-expression.
On the other hand, a ‘?’ form may not be used
as an argument to a procedure application.
consequent ::= expression alternate ::= expression
An if
expression is evaluated as follows:
first, the test-or-match is
evaluated. If it it true, then consequent is
evaluated and its values are returned. Otherwise alternate is
evaluated and its values are returned. If test yields #f
and no alternate 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) ⇒ 'invalid
The consequent and alternate expressions are in tail
context if the if
expression itself is.
(else
expression…)
¶cond-clause ::=(
test-or-match body)
|(
test=>
expression)
A cond
expression is evaluated by evaluating the test-or-matchs
of successive cond-clauses in order until one of them
evaluates to a true value. When a test-or-match is true
value, then the remaining expressions in its cond-clause
are evaluated in order, and the results of the last expression in
the cond-clause are returned as the results of the entire
cond
expression. Variables bound by the test-or-match
are visible in body.
If the selected cond-clause contains only the test-or-match and no
expressions, then the value of the last test-expression is returned as the
result. If the selected cond-clause uses the =>
alternate
form, then the expression is evaluated. Its value must be a
procedure. This procedure should accept one argument; it is called on
the value of the test-expression and the values returned by this procedure
are returned by the cond
expression.
If all test-or-matchs evaluate to #f
, and there is no else
clause, then the conditional expression returns unspecified values; if
there is an else
clause, then its expressions 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)) ⇒ 2
For a cond-clause of one of the following forms:
(test expression*) (else expression expression*)
the last expression is in tail context if the cond
form
itself is. For a cond clause of the form:
(test => expression)
the (implied) call to the procedure that results from the evaluation of
expression is in tail context if the cond
form itself
is.
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.
Each datum in the entire case
expression should be distinct.
A case
expression is evaluated as follows.
eqv?
against the data represented by the datums of
each case-clause in turn, proceeding in order from left to
right through the set of clauses.
case
expression. Otherwise, the comparison process continues.
case
expression; otherwise the result of case
expression is unspecified.
If the selected case-clause or case-else-clause
uses the =>
alternate
form, then the expression 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 the key and the
values returned by this procedure are returned by the case
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))) ⇒ c
The last expression of a case clause is in tail context if
the case
expression itself is.
The match
form is a generalization of case
using patterns,
match-key ::= expression match-clause ::=(
pattern [guard] body)
The match-key is evaluated, Then the match-clauses are tried in order. The first match-clause whose pattern matches (and the guard, if any, is true), is selected, and the corresponding body evaluated. It is an error if no match-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 by match
:
Matching against a list of values.
However, this is easy to simulate using a guard using memq
,
memv
, or member
:
;; 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))
If there are no test-or-match forms, #t
is returned.
If the and
is not in test-or-match context,
then the last sub-expression (if any) must be a test-expression,
and not a ‘?’ form. In this case the
test-or-match expressions are evaluated from left to right until
either one of them is false
(a test-expression is false or a ‘?’ match fails),
or the last test-expression is reached. In the
former case, the and
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 in test-or-match context,
then the last sub-form can be ‘?’ form.
They are evaluated in order: If one of them is false,
the entire and
is false; otherwise the and
is true.
Regardless, any bindings made by earlier ‘?’ forms are visible in later test-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)) ⇒ #t
The and
keyword could be defined in terms of if
using
syntax-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 the and
expression itself is.
If there are no test-expressions, #f
is returned. Otherwise, the
test-expressions are evaluated from left to right until a
test-expression returns a true value val or the last
test-expression is
reached. In the former case, the or
expression returns val
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 of if
using
syntax-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 the or
expression itself is.
The not
procedure returns #t
if test-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
If test-expression is true, evaluate each form in order, returning the value of the last one.
If test-expression is false, evaluate each form in order, returning the value of the last one.
Next: Variables and Patterns, Previous: Boolean values, Up: Program structure [Contents][Index]