定义 cond 是否不起作用

define if with cond doesn't work

我尝试实现一个 "special-if",假设它的行为与常规 "if" 一样,带有 cond。这是代码:

(define (special-if pre act alt)
  (cond (pre act)
        (else alt)))

为了测试这是否有效,我用这个 "special-if":

写了一个阶乘函数
(define (factorial n)
       (special-if (= n 1)
           1
           (* n (factorial (- n 1)))))

但是,当我评估 (factorial 3) 时,它会永远运行。似乎谓词部分 (= n 1) 从未被评估过。谁能告诉我为什么这行不通?谢谢

你的专项if恐怕注定要失败。请记住:if 是一种具有不同计算规则的特殊形式(而 cond 是使用 if 实现的宏),这就是为什么像这样的表达式即使被零除也能正常运行:

(if true 'ok (/ 1 0))
=> 'ok

... 而你的 special-if 会引发错误,因为它使用适用于程序的正常评估规则,这意味着它的所有参数都在 之前 被评估执行过程:

(special-if true 'ok (/ 1 0))
=> /: division by zero

现在你明白为什么你的代码失败了:在递归的底部,当 n1 both 时,结果和替代将执行!

(special-if (= 1 1)
    1                          ; this expression is evaluated
    (* 1 (factorial (- 1 1)))) ; and this expression too!

... 而 factorial 将愉快地继续执行 0-1-2 等值,从而导致死循环。底线:您必须使用现有的特殊形式(或定义新的宏)来实现条件行为,用户定义的标准过程在这里根本行不通。

您听说过 为什么 您的 special-if 不起作用,但您接受了一个没有告诉您如何使其起作用的答案:

(define-syntax special-if 
  (syntax-rules ()
      ((_ pre act alt)
       (cond (pre act)
             (else alt)))))

定义了一个宏,在编译时展开。每次编译器看到与此模式匹配并以 special-if 开头的内容时,它就会被显示的模板替换。因此,preactalt 在您的 special-if 表单变成 cond 表单之前不会被评估。

使用 Scheme 很难理解宏的工作原理,因为 Scheme 尽其所能地隐藏真正发生的事情。如果您使用的是 Common Lisp,宏将是一个简单的函数,它将未编译代码片段(以列表、符号、字符串和数字的形式)作为参数,并将 returns 未编译代码作为其值。在 Common Lisp 中,special-if 只是 return 一个列表:

(defmacro special-if (pre act alt)
   (list 'cond (list pre act)
               (list t alt)))

方案宏的工作方式相同,除了列表、符号等被包装在还包含词法信息的 "syntax objects" 中,而不是使用列表 carcdr、Scheme 和 Racket 等运算符提供了模式匹配和模板引擎,可深入研究语法对象并处理额外数据(但不允许您直接处理任何数据) ).