case
Scheme原生提供了if语法,用于判断十分便利,但是对于某些多于一个的条件,就只能嵌套写if来实现了,写起来有些不便,Chez Scheme提供了case语法来处理这种情况,这与Java中的switch语法非常相似。
我们来看看case的语法:
(case expr0 clause1 clause2 …)
除了最后一个clause之外,每个子句都必须采用以下形式之一:
- ((key …) expr1 expr2 …)
- (key expr1 expr2 …)
每一个key值都应该是不同的,最后一个子句要么是上述那种形式,或者是一个像下面这样的else子句
- (else expr1 expr2 …)
那么返回值是什么呢?
(define p
(lambda (x)
(case x
[("abc" "def") 'one '1]
[((a b c)) 'two]
[else #f])))
(p (string #\d #\e #\f)) ⇒ 1
(p '(a b c)) ⇒ two
(p "eee") ⇒ #f
上面的例子定义了一个函数p,接收一个参数x
- 如果x为字符串"abc"或者"def",则返回1;
- 如果x为列表((a b c),则返回two
- 其他情况返回#f
可见,有了case语法多条件判断写起来就方便很多,并且代码也容易读了,当然这里也可以用cond来写,这里只是为了描述case的语法而没有使用cond
再看一个例子,就不用解释了:
(let ([ls '(ii iv)])
(case (cadr ls)
[i 1]
[ii 2]
[iii 3]
[(iiii iv) 4]
[else 'out-of-range])) ⇒ 4
record-case
来看看另一个很类似的扩展,也十分有用,它就是record-case。它可以以record为单位来做条件判断并执行指令。
语法格式:
(record-case expr clause1 clause2 …)
除了最后一个子句之外,每个clause的格式如下:
((key …) formals body1 body2 …)
每一个key都不应该相同, 最后一个clause可能是上述的格式或者是一个else子句:
(else body1 body2 …)
expr必须是一个pair。Chez会拿(car expr)与各个子句中的key进行比较(用eqv?)来确定哪一个clause匹配, 然后(cdr expr)将与formals绑定。
来看换一个例子:
(define calc
(lambda (x)
(record-case x
[(add) (x y) (+ x y)]
[(sub) (x y) (- x y)]
[(mul) (x y) (* x y)]
[(div) (x y) (/ x y)]
[else (assertion-violationf 'calc "invalid expression ~s" x)])))
(calc '(add 3 4)) => 7
(calc '(div 3 4)) => 3/4