为什么 cond 在 Scheme 中是一种特殊形式,而不是函数?
Why is cond a special form in Scheme, rather than a function?
(defun triangle-using-cond (number)
(cond
((<= number 0) 0) ; 1st
((= number 1) 1) ; 2nd
((> number 1) ; 3rd
;; 4th
(+ number
(triangle-using-cond (1- number))))))
我对Cond的了解
- 它允许多个测试和替代表达式
- 它有预先指定的评估顺序。比如第一个条件总是判断是否正确
我无法区分的一件事是 cond 与函数的不同之处!
一个函数调用(e0 e1 e2)
是这样计算的
1. e0 is evaluated, the result is (hopefully) a function f
2. e1 is evaluated, the result is a value v1
3. e2 is evaluated, the result is a value v2
4. The function body of `f` is evaluated in an environment in which
the formal parameters are bound to the values `v1` and `v2`.
请注意,所有表达式 e0
、e1
和 e2
在函数主体被激活之前计算。
这意味着像 (foo #t 2 (/ 3 0))
这样的函数调用将在计算 (/ 3 0)
时导致错误 - 在控制权移交给 foo
的主体之前。
现在考虑特殊形式if
。在 (if #t 2 (/ 3 0))
中,表达式 #t
被求值,由于值非假,第二个表达式 2
被求值,结果值为 2。这里 (/ 3 0)
永远不会被求值。
相反,如果 if
是一个函数,那么表达式 #t
、2
和 (/ 3 0)
在函数体被激活之前计算。现在 (/ 3 0)
将产生错误 - 即使不需要该表达式的值。
简而言之:在将控件传递给函数体之前,函数调用将始终评估所有参数。如果不对某些表达式求值,则需要特殊形式。
此处 if
和 cond
是形式的示例,它们不会计算所有子表达式 - 因此它们需要是特殊形式。
如果 cond
不是特殊形式,则表达式:
((> number 1) ;;3rd
(+ number (triangle-using-cond (1- number))))
会导致:
一个无限循环,因为 triangle-using-cond
会通过尾部调用 (triangle-using-cond (1- number))
.
递归调用自身
或者,最后一个表达式将尝试将值 #f
或 #t
应用为函数(这在 type-2 Lisp 中是可能的,例如 ANSI Common Lisp , 但在 Racket 或 Scheme 等类型 1 Lisp 中是不可能的) 并产生错误。
cond
之所以成为一种特殊形式,是因为它的参数是惰性求值的,而 Scheme 或 Common Lisp 中的函数是急切求值的。
正如已经回答的那样,在计算应用 f 的结果之前,对调用某个函数 f 的所有参数进行求值。然而,这是否意味着 cond
或 if
或两者都应该是特殊形式?
嗯,首先,如果你有 if
,你可以很容易地用嵌套测试模拟 cond
。相反,if
只是 cond
的退化形式。所以你可以说其中之一有一个特殊的形式就足够了。我们选择 if
因为它更容易指定。
那么if
应该是特别的吧?
其实不需要...
如果基础问题是"is if
expressible in terms of a smaller set of special forms?",那么答案是是:只需实施if
in terms of functions:
(define true-fn (lambda (then else) (then)))
(define false-fn (lambda (then else) (else)))
只要你可以 return 一个布尔值,你就 return 上面的函数之一。
例如,您可以决定将 #t
和 #f
绑定到这些函数。
注意他们如何调用两个输入参数之一。
((pair? x) ;; returns either true-fn or false-fn
(lambda () (+ x 1))
(lambda () x))
...但是为什么要用 lambda 演算编写代码?
有条件地评估代码确实是计算的基本操作。试图找到一种你无法表达的最小特殊形式,从程序员的角度来看,这会直接导致 较差 编程语言,但是 "clean" 核心语言是。
从某种角度,if
形式(或cond
)是必要的因为没有它们,就很难以 compiler/interpreter 可以有效处理的方式表达条件执行。
This document referenced by 讨论使用闭包实现 if
,并得出结论:
However, the syntactic inconvenience would be so great that even
Scheme defines if as a special form.
(defun triangle-using-cond (number)
(cond
((<= number 0) 0) ; 1st
((= number 1) 1) ; 2nd
((> number 1) ; 3rd
;; 4th
(+ number
(triangle-using-cond (1- number))))))
我对Cond的了解
- 它允许多个测试和替代表达式
- 它有预先指定的评估顺序。比如第一个条件总是判断是否正确
我无法区分的一件事是 cond 与函数的不同之处!
一个函数调用(e0 e1 e2)
是这样计算的
1. e0 is evaluated, the result is (hopefully) a function f
2. e1 is evaluated, the result is a value v1
3. e2 is evaluated, the result is a value v2
4. The function body of `f` is evaluated in an environment in which
the formal parameters are bound to the values `v1` and `v2`.
请注意,所有表达式 e0
、e1
和 e2
在函数主体被激活之前计算。
这意味着像 (foo #t 2 (/ 3 0))
这样的函数调用将在计算 (/ 3 0)
时导致错误 - 在控制权移交给 foo
的主体之前。
现在考虑特殊形式if
。在 (if #t 2 (/ 3 0))
中,表达式 #t
被求值,由于值非假,第二个表达式 2
被求值,结果值为 2。这里 (/ 3 0)
永远不会被求值。
相反,如果 if
是一个函数,那么表达式 #t
、2
和 (/ 3 0)
在函数体被激活之前计算。现在 (/ 3 0)
将产生错误 - 即使不需要该表达式的值。
简而言之:在将控件传递给函数体之前,函数调用将始终评估所有参数。如果不对某些表达式求值,则需要特殊形式。
此处 if
和 cond
是形式的示例,它们不会计算所有子表达式 - 因此它们需要是特殊形式。
如果 cond
不是特殊形式,则表达式:
((> number 1) ;;3rd
(+ number (triangle-using-cond (1- number))))
会导致:
一个无限循环,因为
triangle-using-cond
会通过尾部调用(triangle-using-cond (1- number))
. 递归调用自身
或者,最后一个表达式将尝试将值
#f
或#t
应用为函数(这在 type-2 Lisp 中是可能的,例如 ANSI Common Lisp , 但在 Racket 或 Scheme 等类型 1 Lisp 中是不可能的) 并产生错误。
cond
之所以成为一种特殊形式,是因为它的参数是惰性求值的,而 Scheme 或 Common Lisp 中的函数是急切求值的。
正如已经回答的那样,在计算应用 f 的结果之前,对调用某个函数 f 的所有参数进行求值。然而,这是否意味着 cond
或 if
或两者都应该是特殊形式?
嗯,首先,如果你有 if
,你可以很容易地用嵌套测试模拟 cond
。相反,if
只是 cond
的退化形式。所以你可以说其中之一有一个特殊的形式就足够了。我们选择 if
因为它更容易指定。
那么if
应该是特别的吧?
其实不需要...
如果基础问题是"is if
expressible in terms of a smaller set of special forms?",那么答案是是:只需实施if
in terms of functions:
(define true-fn (lambda (then else) (then)))
(define false-fn (lambda (then else) (else)))
只要你可以 return 一个布尔值,你就 return 上面的函数之一。
例如,您可以决定将 #t
和 #f
绑定到这些函数。
注意他们如何调用两个输入参数之一。
((pair? x) ;; returns either true-fn or false-fn
(lambda () (+ x 1))
(lambda () x))
...但是为什么要用 lambda 演算编写代码?
有条件地评估代码确实是计算的基本操作。试图找到一种你无法表达的最小特殊形式,从程序员的角度来看,这会直接导致 较差 编程语言,但是 "clean" 核心语言是。
从某种角度,if
形式(或cond
)是必要的因为没有它们,就很难以 compiler/interpreter 可以有效处理的方式表达条件执行。
This document referenced by if
,并得出结论:
However, the syntactic inconvenience would be so great that even Scheme defines if as a special form.