我总是对Clojure中的Symbols和Vars感到困惑.例如,可以肯定地说+是用于表示var的符号,并且此var指向一个可以添加数字的函数的值吗?
那么当我在REPL中输入"+"时,会一步一步地发生什么?
Jou*_*nen 63
有一个符号+,你可以通过引用它来谈论它:
user=> '+
+
user=> (class '+)
clojure.lang.Symbol
user=> (resolve '+)
#'clojure.core/+
Run Code Online (Sandbox Code Playgroud)
所以它解析为#'+,这是一个Var:
user=> (class #'+)
clojure.lang.Var
Run Code Online (Sandbox Code Playgroud)
Var引用了函数对象:
user=> (deref #'+)
#<core$_PLUS_ clojure.core$_PLUS_@55a7b0bf>
user=> @#'+
#<core$_PLUS_ clojure.core$_PLUS_@55a7b0bf>
Run Code Online (Sandbox Code Playgroud)
(@符号只是deref的简写.)当然,获取该函数的常用方法是不引用符号:
user=> +
#<core$_PLUS_ clojure.core$_PLUS_@55a7b0bf>
Run Code Online (Sandbox Code Playgroud)
请注意,词法绑定是一种不同的机制,它们可以隐藏Vars,但您可以通过明确引用Var来绕过它们:
user=> (let [+ -] [(+ 1 2) (@#'+ 1 2)])
[-1 3]
Run Code Online (Sandbox Code Playgroud)
在最后一个例子中,deref甚至可以省略:
user=> (let [+ -] [(+ 1 2) (#'+ 1 2)])
[-1 3]
Run Code Online (Sandbox Code Playgroud)
这是因为Var通过调用自身的deref,将结果转换为IFn并将函数调用委托给它来实现IFn(Clojure函数的接口).
使用defn定义私有函数时使用的可见性机制基于符号上的元数据.您可以通过直接引用Var来绕过它,如上所述:
user=> (ns foo)
nil
foo=> (defn- private-function [] :secret)
#'foo/private-function
foo=> (in-ns 'user)
#<Namespace user>
user=> (foo/private-function)
java.lang.IllegalStateException: var: #'foo/private-function is not public (NO_SOURCE_FILE:36)
user=> (#'foo/private-function)
:secret
Run Code Online (Sandbox Code Playgroud)
这个答案与其他答案没有太大区别,它只是不假设您最初希望学习几个新功能和概念只是为了了解正在发生的事情:
+
是一个符号clojure.core
,默认情况下您的代码可以访问它。+
它用于列表的头部位置时,clojure 将尝试调用该函数(NullPointerException
如果这个 Var 恰好没有指向一个函数)。如果作为参数提供给另一个函数,该函数也可以调用它。这就是函数调用的工作原理。大多数或所有语言都使用符号表。作为一种有点动态的语言,Clojure 使用这个额外的间接层(Symbol ? Var ? 函数,而不仅仅是 Symbol ? 函数),以便动态重写哪个函数与哪个符号相关联?更可行和优雅,这有时是初学者好奇的来源。
由于其他答案有些过分强调,否则您可能会执行诸如引用它 ( ) 之类的花哨的东西'+
来避免对其进行评估,或者甚至检查它class
和/或resolve
好像您有兴趣验证它是什么 ( class
) 或它所在的命名空间在 ( resolve
) 您还可以查看它指向的 varvar
或#'
。如果您正在编写宏或者您非常喜欢实验,您通常会做那些奇特的事情,尤其是在 repl 中工作时;根据您编写宏的风格,您实际上可能会在其中引用很多内容。
作为一种有点灵活的语言,clojure 公开了用于获取 Symbol 的 api ?无功?功能自行行走。您通常不会仅使用函数就这样做,因为显然这会很无聊且多余,但可以在此处使用它来说明该过程:
(deref (resolve '+))
Run Code Online (Sandbox Code Playgroud)
即,符号首先被解析为它的 Var,然后是 Var 所指向的东西。这只是说明了到达函数(Symbol ? Var ? 函数)的两步过程,它发生在幕后。我希望你避免阅读这个额外的部分。
原始问题的答案很简单:是的。
归档时间: |
|
查看次数: |
5573 次 |
最近记录: |