【问题标题】:Why are variables in list cormprehensions not considered is mutable state in clojure?为什么不考虑 list cormprehensions 中的变量是 clojure 中的可变状态?
【发布时间】:2022-11-30 00:35:31
【问题描述】:

在 Clojure 中,每个变量都是不可变的。但是当我像下面的例子一样使用列表理解时,elem 变量似乎是可变的,因为每次 elem 被 1 覆盖,然后被 2 覆盖,然后被 3 覆盖,或者不是?

(for [elem [1 2 3]] 
  elem)

这是允许可变性的地方还是我遗漏了什么?

【问题讨论】:

    标签: clojure


    【解决方案1】:

    “突变”是指现有变量改变其内容。如果你有一个对变量的引用,你可以观察到这一点,查看它一次,将其值记为 X,然后再次查看同一个变量,注意它的值现在是 Y。这不是列表中发生的事情理解。

    首先,让我们谈谈我希望你同意的一件事不是变异:使用不同的值多次调用一个函数。假设我们有

    (defn triple [x]
      (* x 3))
    

    如果我们写[(triple 1) (triple 2)],我们是否说x发生了变异?当然不是。函数 triple 有两个不同的调用,每个调用都有不同的 x 值,但它们不是同一个变量:它们是 x 的不同实例。

    列表理解是同一回事。主体是一个函数,它对每个输入进行一次评估。它没有就像一个函数,因为没有 fn,但它确实是一个,无论是技术上(它宏扩展到 fn 的主体)还是哲学上(它处理输入的方式与上面的 triple 函数相同)。 (for [x xs] (f x)) 与写 (map f xs) 没有什么不同,后者不需要修改。

    通常当新手担心 Clojure 中的突变时,他们担心的是let,它允许您替换现有的绑定:

    (let [x 1
          _ (prn x)
          x 2]
      (prn x))
    

    这打印出1 2: 这不就证明x 发生了变异吗?不,它没有:旧的 x 仍然存在,它只是被隐藏了,所以你不能再引用它了。你可以通过使用一个函数来证明这一点,让你引用旧的x

    (let [x 1
          f (fn [] x)
          x 2]
      (prn (f) x))
    

    这仍然打印1 2,即使这两个打印都发生在x绑定到2之后。这是因为f仍然看到旧的x。新的x是一个无关的同名变量;您不妨将其命名为y 并重命名对它的所有引用。

    【讨论】:

      【解决方案2】:

      here 所述,值和身份之间的区别很重要。如果一个身份似乎发生了变化,那是因为它随着时间的推移与不同的状态值相关联。

      【讨论】:

        【解决方案3】:

        如果您有 C/C++ 背景,那么认为 elem 的行为类似于指向常量对象的非常量指针可能会有所帮助。

        如果您有 Python/Java 背景,认为您正在遍历的集合中的值是不可变的可能会有所帮助。

        无论如何,不​​变性问题是关于集合中元素的断言,而不是关于elem

        【讨论】:

        • 但事实并非如此。 elem 是指向 const 对象的 const 指针。
        • 你确定@amalloy? const 指针在其生命周期内不能指向两个不同的对象;但是,elem 在迭代期间绑定到不同的“对象”。
        • 是的,如果您阅读了我的回答,我会解释说没有重新绑定变量,只是调用具有不同参数的函数。共有三个不同的elem 变量,每个变量都永久固定为输入列表中的一个数字。
        • 如果您的 for 循环返回一个闭包,这种区别就变得更加重要。考虑(let [fs (for [x [1 2 3]] (fn [y] (+ x y)))] (map (fn [f] (f 10)) (reverse fs)))。我们创建了一个包含 3 个闭包的列表,每个值 x 一个。然后我们以相反的顺序调用该列表中的函数,我们可以及时回顾为每个函数捕获的特定x。我希望您会同意,没有任何带有指向 const 对象的非常量指针的循环可以模仿这种行为。 (事实上​​,用 for 循环做这个是 Python 中的一个常见陷阱,因为它使用单个变量!)。
        • 你是对的,但这已经是一个“这里有龙”的区域;-) 我的回答假设原始发帖人的印象是 elem 是可变的——我只是想提供一个第一方向。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-04-05
        • 1970-01-01
        • 2011-10-07
        • 2016-08-09
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多