有谁能解释这段代码?

时间:2010-09-03 07:37:16

标签: clojure types

1: user=> (def some-account {:number :any­-number :balance :any­-balance :bank :any­-bank})
2: #'user/some-account
3: user=> (contains? some-account :bank)
4: true
5: user=> (assoc some-account :owner :any-owner)
6: {:owner :any-owner, :number :any­-number, :balance :any­-balance, :bank :any­-bank}
7: user=> (contains? some-account :owner)
8: false
9: user=> (def some-account (assoc some-account :owner :any-owner))
10: #'user/some-account
11: user=> (contains? some-account :owner)
12: true
13: user=> (dissoc some-account :owner)
14: {:number :any-­number, :balance :any­-balance, :bank :any-­bank}
15: user=> (contains? some-account :owner)
16: true

任何人都可以解释这段代码吗?

为什么在(assoc some-account :owner :any-owner)之后,(contains? some-account :owner)会返回false

为什么,只有在(def some-account (assoc some-account :owner :any-owner))(contains? some-account :owner)返回true

为什么在(dissoc some-account :owner)之后,(contains? some-account :owner)会返回true

我本能地尝试说(def some-account (assoc some-account :owner :any-owner))。但为什么这样做呢?

5 个答案:

答案 0 :(得分:6)

Clojure中的地图是不可变的。

也就是说,更新功能而不是修改原始地图,返回一个新的更新地图。

尝试以下方法:

user=> (def some-account {:number :any­-number :balance :any­-balance :bank :any-bank})
#'user/some-account
user=> (contains? some-account :bank)
true
user=> (def updated-map (assoc some-account :owner :any-owner))
#'user/updated-map
user=> (contains? updated-map :owner)
true
user=>

答案 1 :(得分:3)

值得注意的是,当更新功能生成新地图时,它们不会复制旧地图它们会生成一个新的地图,它共享所有未更改旧部分的部分并且只替换更改所需的部件。

这种结构共享对于所有具有[不可变数据结构] [1]

的函数式语言非常重要

[1]:http://clojure.org/functional_programming#Functional编程 - 不可变数据结构

答案 2 :(得分:2)

在Clojure中,所有数据类型都是不可变的。因此,assoc地图上的some-account操作不会对其进行更改(与Java中put上的java.util.Map操作不同)并生成新地图。这就是countain?操作返回false的原因。当你这样做

(def some-account (assoc some-account :owner :any-owner))

您正在捕获assoc操作的返回值并将其分配给some-account变量。从某种意义上说,你正在重新定义它。所以稍后contain?操作返回true。

答案 3 :(得分:1)

因为assoc和dissoc返回新的objekts并且不会更改某个帐户

答案 4 :(得分:1)

想象一下,您使用的是数字而不是地图:

user> (def s 3)
#'user/s
user> (= s 3)
true
user> (+ 1 s)
4
user> (= s 4)
false
user> (def s (+ 1 s)) ;;don't do this! changing definitions shouldn't be used in a program, only at the REPL for trying things out!
#'user/s
user> (= s 4)
true
user> (- s 1)
3
user> (= s 4)

在Clojure中,大多数值的行为与数字相似。有一些可变的东西,但它们隐藏在神秘的界面背后。如果没有它们,可以完成大量的编程。

但是我们如何在不改变变量的情况下进行编程?您可能已经看过阶乘函数

(defn factorial [n]
        (if (< n 2) 1
            (* n (factorial (dec n)))))

user> (factorial 5)
120

这是一个类似的功能,以相同的方式构建地图

(defn char-map [n]
        (if (< n 0) {}
            (assoc (char-map (dec n)) n (char n))))

user> (char-map 10)
{various control characters..}

这种风格起初很奇怪,但最终变得自然。当我想到这些天要编程的东西时,我经常会想到在命令循环之前的递归解决方案。

他们是两种看待同一事物的不同方式。

通常很容易在它们之间进行转换,因此如果您能想到一种方法,那么您已经想到了另一种方法。但这确实需要练习,比如学习说拉丁语。

在创建它们之后,如果事情没有改变,思路清晰度和线程安全性有一些优点。数学家似乎更喜欢它。