如果您编写(+ 2 3)
之类的内容,+
将被视为函数,如果+
没有与之关联的任何函数定义,则会发生错误。
如果你写的是(let (a b c))
,(a b c)
被读作数据。
lisp如何决定?
答案 0 :(得分:5)
这里有两个基本的lisp概念:
阅读是将文本转换为lisp对象的行为。诸如数字和列表之类的Lisp对象具有所谓的读取表单,这是一种可以读入对象的文本表示。它通常与打印表单相同。如果您来自Java等语言,则 toString()会提供对象的打印形式。没有相同的读取概念,因为Lisp具有有趣且强大的属性,Lisp源代码是一个lisp对象。
重要的是要注意阅读与评估不同,尽管许多对象都是自我评估的。例如,数字是一个在评估时返回自身的对象。说许多表单自我评估会更常见,但你应该记住,上下文中的“表单”通常与“lisp对象”同义,暗示对象将被评估。
考虑在REPL中运行简单程序时会发生什么可能会有用。回想一下,“REPL”代表“读取,评估,打印,循环”,而Lisp是这些步骤之间差异真正明确的语言。
考虑列表程序:
161
在REPL中运行时,结果如下:
161
这里会发生以下情况:
符号的阅读形式将是abc
之类的文本。符号评估它们所持有的变量。让我们在REPL中运行程序abc
:
abc
该程序实际上会产生错误:
eval-last-sexp-1:符号作为变量的值为void:abc
这里发生的是:
特殊形式setq
会将符号设置为指向变量。更多关于以下内容。
从这里开始,Lisp就像大多数语言一样。调用(+ 1 (+ 2 3))
将使用加号函数的命令式语言执行与plus(1, plus(2,3))
相同的操作。整个表达式将为红色以构建列表对象(+ 1 (+ 2 3 ))
,该列表对象是三个元素+
,1
和列表(+2 3)
的列表。然后,作为函数调用的外部+
将使解释器评估自我评估的对象1
和(+ 2 3)
,最终将评估为5。 +
将获取两个已评估的对象1
和5
,然后添加它们,并返回6
。
但是,Lisp具有所谓的特殊形式。特殊表单可以跳过评估步骤,只使用原始对象。例如,setq
是一种特殊形式,用于评估第二个参数,但不是第一个参数。
(setq a (+ 2 3))
将不评估符号“a”,但将采用符号“a”并将其分配给(+ 2 3)
评估的内容,即数字5.然后,调用< / p>
a
REPL中的将打印5
。
所以回答原来的问题......“让”是一种特殊形式,因此不会立即评估其论点:)
宏也不会评估他们的论点,但原始问题可能没有必要进行全面讨论。
答案 1 :(得分:1)
如果你写(let(a b c)),(a b c)被读作数据。
不是真的。一切都是一样的。首先阅读Lisp表单。充分。评估来得更晚。评估有所不同。
LET
表达式是一种特殊形式,表单根据特殊规则进行评估。
请参阅Emacs Lisp手册:Parts of let Expression。
Lisp
(* a b)
(let ((a 1)) a)
。这些表单通常是内置的,不能由用户扩展。(defun foo () nil)
标识符是列表中的第一个元素,它告诉我们如何评估表单。