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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/iphone/40.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_Functional Programming - Fatal编程技术网

clojure中的不变性与传递值不同吗?

clojure中的不变性与传递值不同吗?,clojure,functional-programming,Clojure,Functional Programming,我刚刚开始学习Clojure,我没有fp经验,但我注意到的第一件事是非常强调不变性。然而,我对重点有点困惑。看起来您可以轻松地重新定义全局变量,本质上提供了一种更改状态的方法。我能看到的最重要的区别是函数参数是按值传递的,不能在函数中重新定义(定义)。下面是一个repl片段,它显示了我的意思: towers.core=> (def a "The initial string") #'towers.core/a towers.core=> a "The initial stri

我刚刚开始学习Clojure,我没有fp经验,但我注意到的第一件事是非常强调不变性。然而,我对重点有点困惑。看起来您可以轻松地重新定义全局变量,本质上提供了一种更改状态的方法。我能看到的最重要的区别是函数参数是按值传递的,不能在函数中重新定义(定义)。下面是一个repl片段,它显示了我的意思:

 towers.core=> (def a "The initial string")
 #'towers.core/a
 towers.core=> a
 "The initial string"
 towers.core=> (defn mod_a [aStr]
     #_=>   (prn aStr)
     #_=>   (prn a)
     #_=>   (def aStr "A different string")
     #_=>   (def a "A More Different string")
     #_=>   (prn aStr)
     #_=>   (prn a))
 #'towers.core/mod_a
 towers.core=> a
 "The initial string"
 towers.core=> (mod_a a)
 "The initial string"
 "The initial string"
 "The initial string"
 "A More Different string"
 nil
 towers.core=> a
 "A More Different string"

如果我开始理解clojure中的不变性时将其视为传递值,那么我遗漏了什么?

按值调用和不变性是两个完全不同的概念。事实上,变量不变性的优点之一是,这些变量可以通过名称或引用传递,而不会对程序行为产生任何影响


简言之:不要认为它们是相互关联的

请注意,从技术上讲,Java和Clojure(在JVM上)是。在许多情况下,传递的东西是对其他人可能正在阅读的结构的引用,尽管因为它是不变的,所以没有人会从你下面改变。重要的一点是,可变性和不可变性发生在您将引用传递给某物之后,Marcin指出它们确实是不同的

通常clojure脚本/类中很少有“def”d,它主要用于生成类外使用的值。而是在方法中需要时在let绑定中创建值

def用于定义变量,如中所述:

顶级函数和值都存储在变量中,这些变量是 在当前命名空间中使用def特殊形式或 它的衍生物

在函数中使用def并不是生成局部变量,而是创建一个新的全局变量,每次都用一个新的引用替换旧的引用

当您继续使用let时,您将看到不变性是如何工作的,例如使用seqs之类的东西,它可以在没有其他人读过它们的情况下被使用(例如,在java中对列表进行迭代),例如


如您所见,
(first myseq)
从序列中“获取”了一个项目并不重要。因为序列
myseq
是不可变的,所以它仍然是相同的,并且不受其上的操作的影响。另外,请注意,上面的代码中没有一个单独的定义,赋值发生在创建值myseq、f、s和sum的let绑定中(并且在sexp的其余部分中是不可变的)。

我认为Clojure中的不可变性主要存在于(大多数)内置数据结构类型和(大多数)中允许操作的函数。。。呃,不,修改。。。不,真的,从它们构建新的数据结构。有一些类似数组的东西,但你不能修改它们,有列表,但你不能修改它们,有哈希映射,但你不能修改它们,等等,而且使用它们的标准工具实际上创建了新的数据结构,即使在新手看来,它们看起来像是在执行就地修改。所有这些加起来确实是一个很大的区别。

是的,不变性不同于按值传递,您在示例中遗漏了几个重要的细节:

  • 值突变变量再结合。您的代码举例说明了重新绑定,但实际上并没有改变值

  • 阴影。您的本地
    aStr
    将您的全局
    aStr
    隐藏起来,因此您无法看到全局的
    (def a…
    )和
    (def aStr…
    的效果没有区别。您可以验证是否在运行函数后创建了全局变量


  • 最后一点:Clojure不会强迫你完全发挥功能——它有逃生舱口,由你负责地使用它们。重新绑定变量是一种转义图案填充。

    Java数组是按值传递的,但是如果您在一个函数中更改了它们的内容,另一个函数将受到此更改的影响。Clojure向量不会这样做。@noisesmithJava pass-by值很奇怪。传递的值是指向对象的指针,允许您更改对象。但是,我认为,您不能更改指针。Java传递值是Clojure传递值。重要的是传递的值是否具有可变的内部状态。足够公平。当我读到数据是“不可变的”时,我认为这意味着全局变量都是“最终的”(用Java语言)。但看起来不是那样的。我意识到,在封面下,我并没有改变值,但这看起来就像是语义学。下一个使用全局的函数(在我的示例中是a)将获得修改后的字符串。是的,我用let做了一些简单的示例,我想我看到了Clojure如何为您提供一些可靠的工具,以避免踩到您的数据。我只是有点惊讶,我能够处理全局变量。clojure和大多数语言在设计策略上的一个区别是,在clojure中,可变全局状态通常被认为比可变局部状态更可取。lisp的传统是完全在交互环境中开发,这使得重新定义顶级绑定的能力成为必要。“能够处理全局变量”-我完全理解,当我第一次开始学习clojure时,我也有同样的想法,“等等,你告诉我这都是不可变的,但我可以很容易地重新定义它!”,因此,当我意识到def只是用来暴露有用的东西的外层时,我提出了我自己的“啊,我明白了”时刻,并且在尝试东西的时候也在REPL中(def做这项工作(我写的一些函数等等)。老实说,我想这应该是公认的答案。
    (let [myseq (seq [1 2 3 4 5])
              f (first myseq)
              s (second myseq) 
            sum (reduce + myseq)]
      (println f s sum))
    ;; 1 2 15