Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/clojure/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Clojure中符号和变量的区别_Clojure - Fatal编程技术网

Clojure中符号和变量的区别

Clojure中符号和变量的区别,clojure,Clojure,我对Clojure中的符号和变量总是有点困惑。 例如,可以安全地说+是一个用来表示变量的符号,而这个变量指向一个值,这个值是一个可以添加数字的函数吗 那么,当我在REPL中输入“+”时,一步一步地发生了什么 符号被限定为名称空间,在本例中为clojure.core 然后在一些符号表中有+表示变量的信息 当计算此变量时,结果是函数值 见: 名称空间是从简单(非限定)符号到变量和/或类的映射。可以使用def或其任何变体将变量固定在名称空间中,在这种情况下,它们有一个简单的名称符号和对其包含名称空间的

我对Clojure中的符号和变量总是有点困惑。 例如,可以安全地说+是一个用来表示变量的符号,而这个变量指向一个值,这个值是一个可以添加数字的函数吗

那么,当我在REPL中输入“+”时,一步一步地发生了什么

  • 符号被限定为名称空间,在本例中为clojure.core
  • 然后在一些符号表中有+表示变量的信息
  • 当计算此变量时,结果是函数值
  • 见:

    名称空间是从简单(非限定)符号到变量和/或类的映射。可以使用def或其任何变体将变量固定在名称空间中,在这种情况下,它们有一个简单的名称符号和对其包含名称空间的引用,并且名称空间将该符号映射到同一个变量。名称空间还可以使用REFERE或use包含从符号到其他名称空间中固定变量的映射,或使用导入从符号到类对象

    因此,步骤1和步骤2基本上是统一的:名称空间是符号表


    关于第3步:我喜欢变量的定义,它们是值的名称的组合。符号是变量的名称,对其求值将得到其值。

    有一个符号+,您可以通过引用它来谈论它:

    user=> '+
    +
    user=> (class '+)
    clojure.lang.Symbol
    user=> (resolve '+)
    #'clojure.core/+
    
    因此它解析为#'+,这是一个变量:

    user=> (class #'+)
    clojure.lang.Var
    
    变量引用函数对象:

    user=> (deref #'+)
    #<core$_PLUS_ clojure.core$_PLUS_@55a7b0bf>
    user=> @#'+
    #<core$_PLUS_ clojure.core$_PLUS_@55a7b0bf>
    
    在最后一个示例中,甚至可以忽略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
    
    user=>(ns-foo)
    无
    foo=>(defn-private函数[]:secret)
    #'foo/私有函数
    foo=>(在ns的用户中)
    #
    user=>(foo/private函数)
    java.lang.IllegalStateException:var:#'foo/private函数不是公共函数(无源文件:36)
    user=>(#'foo/私有函数)
    :秘密
    
    这个答案与其他答案没有太大区别,只是不假设您最初希望学习几个新的函数和概念,只是为了了解发生了什么:

  • +
    是位于
    clojure.core
    中的一个符号,默认情况下代码可以访问该符号
  • 在代码中使用时,如果没有任何高级意图,例如引用它或查找它的类,clojure将查找它所指向的Var
  • 如果该变量是一个函数,当在列表的开头位置使用
    +
    时, clojure将尝试调用该函数(
    NullPointerException
    ,如果该变量恰好未指向函数)。如果作为参数提供给 另一个函数,该函数也可以调用它。那是 函数调用是如何工作的

  • 关于总结的进一步意见: 大多数或所有语言都使用符号表。作为一种有点动态的语言,Clojure使用了这个额外的间接层(符号→ 变量→ 功能,而不仅仅是符号→ 因此,动态重写哪个函数与哪个符号相关联更可行、更优雅,这有时是初学者好奇的来源

    正如其他答案有点过分强调的那样,您可能会以其他方式执行一些花哨的操作,比如引用它(
    '+
    ),以避免对其求值,或者甚至使用
    和/或
    解析
    检查它,就好像您有兴趣验证它是什么(
    ),或者它位于哪个命名空间(
    解析
    )。您还可以通过
    var
    #
    查看它所指向的var。如果您正在编写宏或非常喜欢实验,尤其是在repl中工作时,您通常会做这些奇特的事情;根据您编写宏的风格,您可能会在宏中引用很多内容

    还有一个特别探索的人的精美插图: 作为一种灵活的语言,clojure公开了获取符号的api→ 变量→ 你可以自己走路。仅使用函数通常不会这样做,因为这显然是无聊和多余的,但这里可以用它来说明过程:

    (deref (resolve '+))
    
    也就是说,首先将符号解析为其Var,然后到达Var所指向的对象。这只是说明了获得函数(符号)的两步过程→ 变量→ 函数),它发生在幕后。我希望你避免读这额外的部分


    TL;博士
    原始问题的答案很简单:是的。

    我发现理解符号、函数、文字和变量之间的差异对于探索正在发生的事情是必要的

  • (def one(fn[]1))
    ⇒ <代码>#示例/一。它引用函数
    #函数[示例/一]
  • (def x one)
    #示例/x
    引用函数
    #函数[example/one]
  • (定义y'one)
    ⇒ <代码>#示例/y引用符号
    one
  • (def z#one)
    #示例/z
    引用var
    #示例/one
  • 准确地说,
    one
    是一个解析为var
    #示例/one
    的符号。var引用一个函数,
    #函数[example/one]
    ,它返回文本
    1

    每个
    def
    。var由
    #示例/x
    中的
    #
    语法表示。每个变量引用一个值

    根据,符号在求值时解析为值、特殊形式或错误。因此可能会有点混乱,因为没有提到var:

  • (键入一)
    ⇒ <代码>示例$1
  • (x型)
    ⇒ <代码>exa
    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
    
    (deref (resolve '+))