Chez Scheme中的case扩展

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