Clojure 学习/评估
外观
字符串、数字、字符、nil
、true
、false
和关键字自身评估。当评估器遇到这些内容时,它只需将它们原样返回。
当评估器遇到向量或哈希映射时,它会遍历并评估内容,然后返回向量或哈希映射。实际上,如果向量或哈希映射只包含字符串、数字、字符、nil
、true
、false
、关键字以及其他向量或哈希映射,则向量/哈希映射将原样返回。
["eat my shorts" \space 35.6 true {:fred 22 :alison 8}] ; will simply be returned by the evaluator
但是,列表和符号的评估方式不同。
评估器根据符号的类型解析符号。
一个命名空间限定符号解析为映射到指定命名空间中符号的 Var 的根绑定。
hedgehog/rabbit ; a symbol resolving to the root binding of the Var mapped to rabbit in the namespace hedgehog
虽然类可以在命名空间中引用,但命名空间限定符号永远只解析为 Var。如果符号没有命名任何 Var,则会抛出异常。
一个包限定符号(包含 . 的符号)解析为一个类。
java.util.Arrays ; a symbol resolving to the Class Arrays in the package java.util
如果找不到这样的类,则会抛出异常。
非限定符号的解析更加复杂。
- 如果符号是列表中的第一个项目,并且与十几个特殊形式名称之一匹配,则该列表是特殊形式,并且以特殊方式评估(稍后讨论)。
- 如果不是,则该符号可能映射到当前命名空间中引用的类。
- 如果不是,则该符号可能映射到局部变量(局部变量由特殊形式创建,我们将在稍后看到)。
- 如果不是,则该符号可能映射到在当前命名空间中内联或引用的 Var 的绑定。(这可能是根绑定或线程局部绑定,如前所述。)
- 如果不是,则该符号解析为空,并抛出异常。
[为什么类查找必须在局部变量之前完成?局部变量名称不应该优先于类名?]
(另一种理解符号解析的方法是它们解析为 Vars,而 Vars 又依次评估为它们绑定的值。这大体上是正确的,但请注意,命名空间限定符号始终解析为根绑定值,无论线程上下文如何。)
空列表简单地评估为自身。
() ; the evaluator returns this as is
传递给评估器的非空列表应以符号或另一个列表开头。如果列表以符号开头
- 如上所述,以不限定符号开头的列表,该符号匹配特殊形式名称,将以特殊方式评估。
- 否则,该符号可能解析为一个包含宏的 Var(一种特殊类型的函数,我们将在稍后看到),在这种情况下,列表的其余元素将保持未评估,并传递给宏的调用。宏返回的值将替换宏调用,然后进行评估。
- 否则,该符号应解析为一个包含函数的 Var,在这种情况下,列表的其余元素将进行评估(从左到右),然后传递给函数的调用。列表的评估返回函数返回的值。
- 否则,将抛出异常。
例如
(def x 3) ; def is a special form, so this list is evaluated specially (rooster ox (lion 3))
假设rooster
解析为一个宏,则该宏将使用ox
符号和(lion 3)
列表的参数进行调用。但是,如果rooster
解析为一个普通函数,则该函数将使用从ox
解析的值和(lion 3)
评估返回的值作为参数进行调用。
不太常见的是,列表可能以另一个列表开头。在这种情况下,将评估初始列表,并期望它返回一个要调用的宏或函数(或返回一个绑定到宏或函数的 Var)。
((hamster) "moo") ; if (hamster) returns a function, that function is called with the argument "moo"