跳转到内容

Clojure 学习/评估

来自维基教科书,开放世界中的开放书籍

字符串、数字、字符、niltruefalse 和关键字自身评估。当评估器遇到这些内容时,它只需将它们原样返回。

当评估器遇到向量或哈希映射时,它会遍历并评估内容,然后返回向量或哈希映射。实际上,如果向量或哈希映射只包含字符串、数字、字符、niltruefalse、关键字以及其他向量或哈希映射,则向量/哈希映射将原样返回。

["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

如果找不到这样的类,则会抛出异常。

非限定符号的解析更加复杂。

  1. 如果符号是列表中的第一个项目,并且与十几个特殊形式名称之一匹配,则该列表是特殊形式,并且以特殊方式评估(稍后讨论)。
  2. 如果不是,则该符号可能映射到当前命名空间中引用的类。
  3. 如果不是,则该符号可能映射到局部变量(局部变量由特殊形式创建,我们将在稍后看到)。
  4. 如果不是,则该符号可能映射到在当前命名空间中内联或引用的 Var 的绑定。(这可能是根绑定或线程局部绑定,如前所述。)
  5. 如果不是,则该符号解析为空,并抛出异常。

[为什么类查找必须在局部变量之前完成?局部变量名称不应该优先于类名?]

(另一种理解符号解析的方法是它们解析为 Vars,而 Vars 又依次评估为它们绑定的值。这大体上是正确的,但请注意,命名空间限定符号始终解析为根绑定值,无论线程上下文如何。)

列表评估

[编辑 | 编辑源代码]

空列表简单地评估为自身。

()    ; the evaluator returns this as is

传递给评估器的非空列表应以符号或另一个列表开头。如果列表以符号开头

  1. 如上所述,以不限定符号开头的列表,该符号匹配特殊形式名称,将以特殊方式评估。
  2. 否则,该符号可能解析为一个包含的 Var(一种特殊类型的函数,我们将在稍后看到),在这种情况下,列表的其余元素将保持未评估,并传递给宏的调用。宏返回的值将替换宏调用,然后进行评估。
  3. 否则,该符号应解析为一个包含函数的 Var,在这种情况下,列表的其余元素将进行评估(从左到右),然后传递给函数的调用。列表的评估返回函数返回的值。
  4. 否则,将抛出异常。

例如

(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"
华夏公益教科书