Lisp “if”如何计算它的所有参数?
我正在努力深入地学习和理解Lisp编程语言。函数Lisp “if”如何计算它的所有参数?,lisp,Lisp,我正在努力深入地学习和理解Lisp编程语言。函数+按应用程序顺序计算其参数: (+ 1 (+ 1 2)) 将对(+1 2)进行求值,然后对(+1 3)进行求值,但if功能的工作方式不同: (if (> 1 2) (not-defined 1 2) 1) 由于未计算表单(未定义1 2),因此程序不会中断 相同的语法如何导致不同的参数计算?if函数是如何定义的,这样它的参数就不会被计算的?这些参数不会像函数那样被计算,因为if是一个特殊的运算符。特殊运算符可以以任意方式进行计算,这就是为什
+
按应用程序顺序计算其参数:
(+ 1 (+ 1 2))
将对(+1 2)
进行求值,然后对(+1 3)
进行求值,但if
功能的工作方式不同:
(if (> 1 2) (not-defined 1 2) 1)
由于未计算表单(未定义1 2)
,因此程序不会中断
相同的语法如何导致不同的参数计算?
if
函数是如何定义的,这样它的参数就不会被计算的?这些参数不会像函数那样被计算,因为if
是一个特殊的运算符。特殊运算符可以以任意方式进行计算,这就是为什么它们被称为特殊运算符
考虑例如
(if (not (= x 0))
(/ y x))
如果总是计算除法,则可能会有一个明显不是故意的零除法错误。如果不是函数,则它是一种特殊形式。如果您想自己实现类似的功能,可以通过定义宏而不是函数来实现
这个答案适用于普通的Lisp,但对于大多数其他Lisp可能都是一样的(尽管在一些
if
中可能是宏而不是特殊形式)。这样做没有任何意义。示例:(if(ask-user-should-i-quit)(quit)(continue))
。即使用户不想退出,也应该退出吗
如果
不是Lisp中的函数。它是一个特殊的内置操作符。Lisp是几个内置的特殊操作符。请参阅:。这些不是函数。是函数,不是普通函数
这意味着在调用与第一个元素关联的函数之前,对中的rest
元素求值的正常规则是不适用的(因为它类似于)
在编译器和/或解释器中实现这一点的方式是查看复合形式,并根据以下内容决定如何处理它:
- 如果它是一个特殊的操作者,它做它特殊的事情李>
- 如果是a,则其宏函数得到整个形式李>
- 否则,它将被视为一个函数-即使没有定义函数
请注意,某些特殊窗体可以定义为扩展到其他特殊窗体的宏,但某些特殊窗体实际上必须存在
例如,可以根据以下方面定义if
:
反之亦然(更复杂-实际上,cond
是一个宏,通常扩展为一系列if
s)
请注意,系统提供的宏和特殊运算符之间的区别在技术上清晰明了(请参见和),但在意识形态上却模糊不清
一个实现可以自由实现一个公共Lisp特殊操作符
作为一个宏。实现可以自由实现任何宏运算符
作为特殊运算符,但仅当
还提供了宏
Lisp语法是规则的,比其他语言更规则,但它仍然不是完全规则的:例如在
(let ((x 0))
x)
let
不是函数名,((x 0))
是一种不错的形式,其中在第一个位置使用了非lambda形式的列表
有相当多的“特殊情况”(当然仍然比其他语言少得多),其中没有遵循每个列表作为函数调用的一般规则,if
就是其中之一。Common Lisp有很多“特殊形式”(因为绝对最小不是重点),但您可以使用scheme方言中的五种形式来摆脱它:if
、progn
、quote
、lambda
和set代码>(如果需要宏,则为六个)
虽然Lisp的语法并不完全一致,但是代码的底层表示法(仅列表和原子)是相当一致的,表示法的一致性和简单性是元编程(宏)的便利之处
“Lisp没有语法”是一个有一定道理的语句,但它也是“Lisp有两个语法”的语句:一个语法是使用读取器将字符流转换为s表达式,另一个语法是使用编译器/计算器将s表达式转换为可执行代码
Lisp没有语法也是事实,因为这两个级别都不是固定的。与其他编程语言不同,您可以自定义第一步(使用读卡器宏)和第二步(使用宏)。很好地回答了这个问题,但我认为有几个更一般的方面值得一提。正如这个答案和其他人所指出的,if
,作为一个特殊的操作符被内置到语言中,因为它实际上是一种原语。最重要的是,如果
不是一个函数
这就是说,if
的功能可以通过使用函数和普通函数调用来实现,其中所有参数都是经过计算的。因此,条件语句可以在中实现,族中的语言在某种程度上是基于条件语句的,但它没有条件运算符
在lambda演算中,可以将true和false定义为两个参数的函数。参数被假定为函数,true调用其第一个参数,false调用第二个参数。(这是一个微小的变化,只返回其第一个或第二个参数。)
(这显然与Common Lisp中的布尔值不同,nil
为false,其他任何值均为true。)但这样做的好处是,我们可以使用布尔值调用两个函数中的一个,具体取决于布尔值是true还是false。考虑常见的LISP形式:
(if some-condition
then-part
else-part)
如果我们使用上面定义的布尔值,那么计算某些条件将产生true
或 true = λ[x y].(x)
false = λ[x y].(y)
(if some-condition
then-part
else-part)
(lambda () then-part)
(lambda () else-part)
(defconstant true
(lambda (x y)
(declare (ignore y))
(funcall x)))
(defconstant false
(lambda (x y)
(declare (ignore x))
(funcall y)))
(defmacro new-if (test then &optional else)
`(funcall ,test
(lambda () ,then)
(lambda () ,else)))
(new-if (member 'a '(1 2 3))
(print "it's a member")
(print "it's not a member"))))
(FUNCALL (MEMBER 'A '(1 2 3)) ; assuming MEMBER were rewritten
(LAMBDA () (PRINT "it's a member")) ; to return `true` or `false`
(LAMBDA () (PRINT "it's not a member")))