(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与函数的不同之处!
答案 0 :(得分:10)
函数调用(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
是表单的示例,不会评估所有子表达式 - 因此它们需要是特殊表单。
答案 1 :(得分:5)
如果cond
不是特殊形式,则表达式为:
((> number 1) ;;3rd
(+ number (triangle-using-cond (1- number))))
会导致:
无限循环,因为triangle-using-cond
将通过尾调用(triangle-using-cond (1- number))
递归调用自身。
或者,最后一个表达式会尝试将值#f
或#t
作为函数应用(在类型2 Lisp中可以使用ANSI Common Lisp,但不可能在类型1 Lisp中,例如Racket或Scheme)并产生错误。
使cond
成为一种特殊形式的原因是它的参数被懒惰地评估,而Scheme或Common Lisp中的函数则急切地评估它们的参数。
答案 2 :(得分:4)
如前所述,在计算应用 f 的结果之前,将评估对某个函数 f 的调用的所有参数。是否意味着cond
或if
或两者都应该是特殊形式?
嗯,首先,如果您有if
,则可以使用嵌套测试轻松模拟cond
。相反,if
只是cond
的退化形式。所以你可以说其中一个是特殊形式就足够了。我们选择if
,因为它更容易指定。
那么if
会特别吗?
如果基本问题&#34; if
可用较小的特殊表格形式表达?&#34; ,那么答案是是< / em>:只需实施if
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))
有条件地评估代码实际上是计算的基本操作。试图找到一个最小的特殊形式,你无法直接表达,从程序员的角度来看,较差的编程语言,然而&#34; clean&#34;核心语言是。
从某个角度来看,if
表单(或cond
)必要因为没有它们就很难表达条件执行以编译器/解释器可以有效处理的方式执行。
uselpa讨论使用闭包来实现if
,并得出结论:
然而,语法上的不便甚至会如此巨大 Scheme定义是否作为特殊形式。