Racket中为何无法像if-else那样用cond返回过程直接调用?
问题描述
受SICP练习1.4中if语法的启发,我尝试使用cond编写逻辑相似的代码:
#!/usr/bin/env racket #lang racket/base (define (b x) (display (bytes-append #"\033[1m" (string->bytes/utf-8 x) #"\33[m"))) (define (i x) (display (bytes-append #"\033[3m" (string->bytes/utf-8 x) #"\33[m"))) #| (define (formatted-printer s) ((if (equal? s "You have to be bold to do it.\n") b i) s)); 运行正常,写法简洁,我希望用cond实现同等简洁的效果 (define (formatted-printer s) (if (equal? s "You have to be bold to do it.\n") (b s) (i s))); 运行正常,但写法过于冗长|# #| (define (formatted-printer s); 运行正常 (cond ((equal? s "You have to be bold to do it.\n") (b s)) ((equal? s "You have to be Italian in order to eat pasta.\n") (i s)) )) |# (define (formatted-printer s) ((cond ((equal? s "You have to be bold to do it.\n") b) ((equal? s "You have to be Italian in order to eat pasta.\n") i) s))); 运行报错:cond: bad syntax (clause is not a test-value pair) (formatted-printer "You have to be bold to do it.\n") (formatted-printer "You have to be Italian in order to eat pasta.\n")
当我像包裹if表达式那样用双层括号包裹cond时,程序抛出如下语法错误:
cond: bad syntax (clause is not a test-value pair) at: s in: (cond ((equal? s "You have to be bold to do it.\n") b) ((equal? s "You have to be Italian in order to eat pasta.\n") i) s) location...:
代码注释已说明我想要实现的效果:是否可以像使用if那样,仅通过cond选择要调用的操作符(过程),实现同等简洁的写法?
解答
当然可以,报错的核心原因是没有遵守cond的语法规则:
if是固定三分支结构:(if 判断条件 满足时返回值 不满足时返回值),天然覆盖所有情况,不需要额外标记兜底分支cond的每一条分支都必须是(测试表达式 结果表达式...)的成对结构,出错代码里最后单独写的s既没有被括号包裹,也不符合「测试条件+对应返回值」的格式,自然会触发语法错误。
要实现和if版本一致的「先选要调用的过程、再统一传参」的简洁写法,只需要给cond加上用else标记的兜底分支即可,修正后的代码如下:
(define (formatted-printer s) ((cond ((equal? s "You have to be bold to do it.\n") b) ((equal? s "You have to be Italian in order to eat pasta.\n") i) (else i)) ; 兜底分支默认返回斜体打印过程i,可根据实际需求调整 s))
这个写法和之前的简洁版if逻辑完全等价:cond会先根据匹配规则返回对应的打印过程b或i,外层的括号再把s作为参数传入返回的过程执行,不需要在每个分支里重复写传参调用的代码,后续如果要修改传入参数,只需要调整最后调用位置的一处代码即可,维护性更好。
内容的提问来源于stack exchange,提问作者John Smith
相关产品推荐
相关产品推荐

