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

我对康德的了解

  • 它允许多个测试和可选表达式
  • 它具有预先指定的评估顺序。例如,第一个条件将始终评估它是否正确
我无法区分的一点是,是什么使cond不同于函数

函数调用
(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))