【发布时间】:2015-09-06 17:02:04
【问题描述】:
我是 Clojure 的新手,我读到它是一种函数式语言。它说Clojure没有变量,当我找到(def n 5)时,它和变量有什么区别?
之后我可以更改 var 的值,那么它与变量真的有那么不同吗?我不明白其中的区别。
【问题讨论】:
标签: clojure functional-programming
我是 Clojure 的新手,我读到它是一种函数式语言。它说Clojure没有变量,当我找到(def n 5)时,它和变量有什么区别?
之后我可以更改 var 的值,那么它与变量真的有那么不同吗?我不明白其中的区别。
【问题讨论】:
标签: clojure functional-programming
将 def 视为定义常量。可以通过再次调用 def 来更改它,但你 should not do it。
变量的关闭是agents,它是线程安全的。
(def counter (agent 0))
(send counter inc)
@counter
;;=> 1
您也可以在 Java 类中访问该变量。
新课程
(def object (ClassName.))
硒值
(.fieldName object)
设定值
(set! (.fieldName object) 5)
没有变量的“全部”点是使程序自动线程安全。这是因为线程错误将“总是”失败,线程 1 会告诉变量 a 为 1,线程 b 告诉变量 a 为 2,然后出现故障。这也是使用纯函数的原因——没有变量“没有”线程问题。
另请参阅此question:Clojure differences between Ref, Var, Agent, Atom, with examples 和此Clojure: vars, atoms, and refs (oh my)。
将“”视为 80% 或更多,而不是 100%。
【讨论】:
Clojure 没有变量是不正确的,即。 e.可变参考。但是,它们不用于在可以建模为纯数学函数的计算过程中存储和查找。
不变性的概念是处理具体值而不是一个或其他可以更改的引用。就像1 是一个您无法更改的值一样,在Clojure 中,向量[3 2] 是您也无法更改的值。例如。如果您的算法需要将1 附加到该向量,则它需要创建一个新向量,使旧向量保持原样,而在命令式语言中,您可以“更改”该向量,从而破坏可能依赖它的所有内容。不变性的好处是您不必再担心这一点,并且您的代码更不容易出错。
Clojure 实现不可变数据结构的方式是,这些新创建的值可以有效地重用它们所基于的值的大部分内存。它们在读写(即创建新版本)方面提供了与可变对应物几乎相同的性能特征。您可能想了解更多关于 here 的信息,Rich Hickey 在与 Brian Beckmann 的对话中对 this 做了一些出色的解释。
【讨论】:
假设variable 指的是可变存储位置,我想主要区别(取决于您比较的语言)是,如果您动态重新绑定var in Clojure 是基于每个线程的。
但长的答案是,除非您确实需要对可变存储位置的引用,否则您通常不会在 Clojure 中使用 var。
Clojure 支持不变性和使用值而不是引用进行编程。
你可以看Rich Hickey's talk关于价值观。
总结一下,当您在 Clojure 中编程时,您所拥有的是 values ,而不是对可能更改的位置的引用(甚至可能被另一个线程更改)。
所以。
(let [a 1
_ (println a) => prints 1
a 2
_ (println a) => prints 2
])
即使您在该代码中产生“更改a”的错觉,您并没有更改“旧”a,您只是有一个新值。 (如果有人会查看第一个定义,它仍然会看到值 1)。
实际上,您可以将分配序列视为组合函数调用,其中a 在范围内被替换,但根本不是同一个“变量”。
((fn [a]
(println a) => prints 1
((fn [a]
(println a) => prints 2
) 2) 1)
不过,如果您需要一个可变存储,并且可能有许多线程访问该存储,Clojure gives youvars、atoms、refs 等。
【讨论】: