【问题标题】:Why is cond a special form in Scheme, rather than a function?为什么 cond 在 Scheme 中是一种特殊形式,而不是函数?
【发布时间】:2016-02-01 15:10:37
【问题描述】:
(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 与函数的不同之处!

【问题讨论】:

标签: functional-programming scheme programming-languages racket


【解决方案1】:

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

请注意,所有表达式 e0e1e2 在激活函数体之前都会被计算。

这意味着像 (foo #t 2 (/ 3 0)) 这样的函数调用将在评估 (/ 3 0) 时导致错误 - 在控制权移交给 foo 的主体之前。

现在考虑特殊形式if。在(if #t 2 (/ 3 0)) 中,表达式#t 被求值,由于值非假,第二个表达式2 被求值,结果值为2。这里(/ 3 0) 从未求值。

如果相反 if 是一个函数,则表达式 #t2(/ 3 0) 在激活的主体之前被计算。现在(/ 3 0) 将产生错误 - 即使不需要该表达式的值。

简而言之:函数调用将始终评估所有参数,然后将控件传递给函数体。如果不计算某些表达式,则需要特殊形式。

这里的ifcond 是表单示例,它们不会评估所有子表达式 - 因此它们需要是特殊表单。

【讨论】:

  • 注意:Racket 需要从左到右评估函数参数 - 在 R5RS 中,顺序未指定。
【解决方案2】:

如果cond 不是特殊形式,则表达式:

((> number 1)         ;;3rd
 (+ number (triangle-using-cond (1- number))))

会导致:

  • 一个无限循环,因为triangle-using-cond 会通过尾调用(triangle-using-cond (1- number)) 不断递归地调用自己。

  • 或者,最后一个表达式将尝试将值 #f#t 作为函数应用(这在 ANSI Common Lisp 等类型 2 Lisp 中是可能的,但在类型 - 1 Lisp(例如 Racket 或 Scheme)并产生错误。

cond 之所以成为一种特殊形式,是因为它的参数是惰性求值的,而 Scheme 或 Common Lisp 中的函数则急切地求值。

【讨论】:

  • 感谢大家的精彩回复。
  • @ben 我从未听说过“type-1/type-2”Lisp 术语。你能详细说明一下吗? (只是好奇这个区别意味着什么。)
  • @phg 通常,lisps 中的符号映射到值。值可以是常规数据类型以及函数。 "lisp-1" 中的 \1\ 描述了一个具有单个名称空间的 lisp,其中符号 foo 可以映射到任何类型的一个值。 “lisp-2”中的 \2\ 描述了具有两个命名空间的 lisp,一个用于“常规”数据类型,另一个用于函数。 ANSI Common Lisp 是一种 lisp-2,因此符号 foo 可以映射到一个命名空间中的整数值和第二个命名空间中的函数/过程值。它将根据它在表达式中的位置评估为一个或另一个。
  • 啊,好吧,这是我熟悉的东西,虽然我从未听说过它被这样称呼。谢谢。
【解决方案3】:

正如已经回答的那样,调用某个函数 f 的所有参数都会在计算应用 f 的结果之前进行评估。然而,这是否意味着condif 或两者都应该是特殊形式?

首先,如果您有if,您可以轻松地模拟带有嵌套测试的cond。相反,if 只是cond 的退化形式。所以你可以说有一个特殊的形式就足够了。让我们选择if,因为它更容易指定。

那么if 应该特别吗?

其实没必要……

如果基本问题是if 是否可以用一组更小的特殊形式表达?”,那么答案是:只需实现@987654333 @in terms of functions

(define true-fn (lambda (then else) (then)))
(define false-fn (lambda (then else) (else)))

只要您可以返回布尔值,您就可以返回上述函数之一。 例如,您可以决定将#t#f 绑定到这些函数。 注意它们是如何调用两个输入参数之一的。

((pair? x) ;; returns either true-fn or false-fn 
  (lambda () (+ x 1))
  (lambda () x))

...但是为什么要在 lambda 演算中编写代码?

有条件地评估代码实际上是计算的基本操作。试图找到一种你无法表达的最小特殊形式,这直接导致从程序员的角度来看更差的编程语言,但是核心语言是“干净”的。

从某种角度来看if 形式(或 cond)是必要的,因为没有它们,在编译器/解释器可以有效处理的方式。

uselpa 引用的This document 讨论使用闭包来实现if,并得出结论:

但是,语法上的不便是如此之大,以至于 Scheme 将 if 定义为一种特殊形式。

【讨论】:

  • 感谢大家的精彩回复。
猜你喜欢
  • 2011-08-02
  • 2013-06-12
  • 1970-01-01
  • 2011-01-15
  • 1970-01-01
  • 2023-03-30
  • 2015-09-06
  • 2019-12-24
  • 2013-03-21
相关资源
最近更新 更多