Functional programming 为什么cond是Scheme中的一种特殊形式,而不是函数? (使用cond(数字)定义三角形) (续) ((1号);3号 第四 (+数字 (三角形使用cond(1-数字‘‘‘‘‘‘)’)
我对康德的了解Functional programming 为什么cond是Scheme中的一种特殊形式,而不是函数? (使用cond(数字)定义三角形) (续) ((1号);3号 第四 (+数字 (三角形使用cond(1-数字‘‘‘‘‘‘)’),functional-programming,scheme,programming-languages,racket,Functional Programming,Scheme,Programming Languages,Racket,我对康德的了解 它允许多个测试和可选表达式 它具有预先指定的评估顺序。例如,第一个条件将始终评估它是否正确 我无法区分的一点是,是什么使cond不同于函数 函数调用(e0 e1 e2)的计算如下 (defun triangle-using-cond (number) (cond ((<= number 0) 0) ; 1st ((= number 1) 1) ; 2nd ((> number 1) ; 3rd ;; 4th
- 它允许多个测试和可选表达式
- 它具有预先指定的评估顺序。例如,第一个条件将始终评估它是否正确
(e0 e1 e2)
的计算如下
(defun triangle-using-cond (number)
(cond
((<= number 0) 0) ; 1st
((= number 1) 1) ; 2nd
((> number 1) ; 3rd
;; 4th
(+ number
(triangle-using-cond (1- number))))))
请注意,所有表达式e0
、e1
和e2
都是在激活函数体之前计算的
这意味着,在将控制权移交给foo
主体之前,当计算(/30)
时,类似(foo#t2(/30))
的函数调用将导致错误
现在考虑特殊形式<代码>如果。在
(如果#t2(/30))
中,计算表达式#t
,由于值非false,因此计算第二个表达式2
,结果值为2。这里从不计算(/3 0)
相反,如果如果是一个函数,则表达式#t
、2
和,(/3 0)
在激活主体之前进行求值。现在,(/30)
将产生一个错误-即使不需要该表达式的值
简言之:在将控件传递给函数体之前,函数调用将始终计算所有参数。如果不计算某些表达式,则需要特殊形式
此处如果和cond
是表单的示例,它们不计算所有子表达式-因此它们需要是特殊表单。如果cond
不是特殊表单,则表达式:
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`.
将导致:
- 无限循环,因为使用cond的
三角形将通过尾部调用(使用cond的三角形(1-number))
不断递归地调用自己
- 或者,最后一个表达式将尝试将值
#f
或#t
作为函数应用(在ANSI Common Lisp等2型Lisp中可能,但在Racket或Scheme等1型Lisp中不可能),并产生错误
使cond
成为一种特殊形式的原因是,它的参数被惰性地求值,而Scheme或Common Lisp中的函数则急切地求值。正如前面所回答的,调用某个函数f的所有参数都在计算应用f的结果之前求值。然而,这是否意味着cond
,或者if
,或者两者都应该是特殊形式
首先,如果你有if
,你可以很容易地用嵌套测试来模拟一个cond
。相反,if
只是cond
的退化形式。所以你可以说,有一个特殊的形式就足够了。让我们选择if
,因为它更容易指定
如果是特殊的,那么应该是特殊的吗
它真的不需要。。。
如果基本问题是“是否可以用一组较小的特殊形式来表达If
”,那么答案是肯定的:只要实现If
:
只要可以返回布尔值,就可以返回上述函数之一。
例如,您可以决定将#t
和#f
绑定到这些函数。
注意它们是如何调用两个输入参数之一的
(define true-fn (lambda (then else) (then)))
(define false-fn (lambda (then else) (else)))
…但为什么要用lambda演算编写代码?
有条件地计算代码实际上是计算的一项基本操作。无论核心语言多么“干净”,从程序员的角度来看,试图找到一种不能直接表达的最小特殊形式会导致编程语言更差
从某种角度来看,if
形式(或cond
)是必要的,因为如果没有它们,就很难以编译器/解释器可以有效处理的方式来表示条件执行
参考讨论使用闭包实现if
,并得出以下结论:
然而,语法上的不便将是如此之大,以至于
Scheme将if定义为一种特殊形式
您的示例是Common Lisp,而不是Scheme或Racket。您的问题仍然存在。这是关于if
,但对于cond
也是正确的:注意:Racket需要对函数参数进行从左到右的求值-在R5R中,顺序是未指定的。感谢大家添加了精彩的回答。感谢大家添加了精彩的回答。@ben我从未听过这些术语“type-1/type-2”Lisp。你能详细说明一下吗?(只是想知道区别是什么意思。)@phg通常Lisp中的符号映射到值。值可以是常规数据类型,也可以是函数。“Lisp-1”中的\1\描述了一个Lisp,其中符号foo
可以映射到任何类型的一个值。中的\2\lisp-2“描述了一个具有两个名称空间的lisp,其中一个用于“常规”“函数的数据类型和其他类型。ANSI Common Lisp是一个Lisp-2,因此符号foo
可以映射到一个名称空间中的整数值和第二个名称空间中的函数/过程值。它将根据它在表达式中的位置计算为一个或另一个。啊,好吧,这是我所熟悉的,尽管我从未听说过它被这样称呼。谢谢
(define true-fn (lambda (then else) (then)))
(define false-fn (lambda (then else) (else)))
((pair? x) ;; returns either true-fn or false-fn
(lambda () (+ x 1))
(lambda () x))