为何Racket中直接用cond与自定义my-if函数执行结果不同?
为什么自定义的my-if函数和原生cond行为不一致?
问题重现
直接使用cond时,只有第一个符合条件的分支会执行:
(cond (#t (displayln "Cond: should run")) (else (displayln "Cond: shouldn't run")))
输出:
Cond: should run
但用define定义的my-if函数调用时,两个分支的表达式都会执行:
(define (my-if condition statement-if statement-else) (cond (condition statement-if) (else statement-else))) (my-if #t (displayln "My-If: should run") (displayln "My-If: shouldn't run"))
输出:
My-If: should run My-If: shouldn't run
核心原因
这完全是求值策略和宏与函数的本质区别导致的:
- Racket的函数采用严格求值(急切求值):调用函数时,所有传入的参数表达式都会被先计算完成,再将结果传入函数体。所以调用
my-if时,不管condition是#t还是#f,两个displayln表达式都会先被执行一遍。 cond是Racket的宏:宏不是函数,它在代码编译阶段就会展开处理。宏会根据条件判断逻辑,只保留并执行符合条件的分支表达式,不会提前计算所有分支的内容。
如何实现类似cond的my-if?
如果想让my-if拥有cond的分支惰性求值特性,不能用define定义函数,而要用宏来实现:
(define-syntax my-if-macro (syntax-rules () [(my-if-macro condition stmt-if stmt-else) (cond (condition stmt-if) (else stmt-else))])) (my-if-macro #t (displayln "Macro-If: should run") (displayln "Macro-If: shouldn't run"))
此时输出就和原生cond一致了:
Macro-If: should run
内容的提问来源于stack exchange,提问作者in-poster-syndrome
相关产品推荐
相关产品推荐

