Clojure中的符号和变量之间的差异 [英] Difference between Symbols and Vars in Clojure

查看:250
本文介绍了Clojure中的符号和变量之间的差异的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我总是有点困惑的符号和变量在Clojure。
例如,是否可以说+是一个用来表示var的符号,这个var指向一个可以添加数字的函数?


$


    那么,当我在REPL中输入+到一个命名空间,在这种情况下是clojure.core

  1. 然后在一些符号表中有一个信息,+引用var

  2. 有一个符号+,表示你的结果是一个符号。可以引用它:

      user => '+ 
    +
    user => (class'+)
    clojure.lang.Symbol
    user => (resolve'+)
    #'clojure.core / +

    '+,这是一个Var:

      user => (class#'+)
    clojure.lang.Var

    Var引用函数对象:

      user => (deref#'+)
    #< core $ _PLUS_ clojure.core$_PLUS_@55a7b0bf>
    user => @#'+
    #< core $ _PLUS_ clojure.core$_PLUS_@55a7b0bf>

    (@符号只是deref的简写)。是不引用符号:

      user => + 
    #<核心$ _PLUS_ clojure.core$_PLUS_@55a7b0bf>

    请注意,词法绑定是一个不同的机制,它们可以影子Vars,明确指向Var:

      user => (let [+  - ] [(+ 1 2)(@#'+ 1 2)])
    [-1 3]

    在最后一个例子中,deref甚至可以省略:

      user => (let [+  - ] [(+ 1 2)(#'+ 1 2)])
    [-1 3]

    这是因为Var通过调用deref自身来实现IFn(Clojure函数的接口),将结果转换为IFn并将函数调用委托给它。



    当使用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


    I'm always a bit confused about Symbols and Vars in Clojure. For example, is it safe to say that + is a symbol which is used to denote a var, and this var points to a value which is a function that can add numbers?

    So what happens, step by step when I just enter "+" in a REPL?

    1. The symbol gets qualified to a namespace, in this case clojure.core
    2. Then in some symbol table there is the information that + refers to a var
    3. When this var is evaluated, the result is a function-value?

    解决方案

    There's a symbol + that you can talk about by quoting it:

    user=> '+
    +
    user=> (class '+)
    clojure.lang.Symbol
    user=> (resolve '+)
    #'clojure.core/+
    

    So it resolves to #'+, which is a Var:

    user=> (class #'+)
    clojure.lang.Var
    

    The Var references the function object:

    user=> (deref #'+)
    #<core$_PLUS_ clojure.core$_PLUS_@55a7b0bf>
    user=> @#'+
    #<core$_PLUS_ clojure.core$_PLUS_@55a7b0bf>
    

    (The @ sign is just shorthand for deref.) Of course the usual way to get to the function is to not quote the symbol:

    user=> +
    #<core$_PLUS_ clojure.core$_PLUS_@55a7b0bf>
    

    Note that lexical bindings are a different mechanism, and they can shadow Vars, but you can bypass them by referring to the Var explicitly:

    user=> (let [+ -] [(+ 1 2) (@#'+ 1 2)])
    [-1 3]
    

    In that last example the deref can even be left out:

    user=> (let [+ -] [(+ 1 2) (#'+ 1 2)])
    [-1 3]
    

    This is because Var implements IFn (the interface for Clojure functions) by calling deref on itself, casting the result to IFn and delegating the function call to that.

    The visibility mechanism used when you define private functions with defn- is based on metadata on the symbol. You can bypass it by referring directly to the Var, as above:

    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
    

    这篇关于Clojure中的符号和变量之间的差异的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆