我可以以纯函数的方式改变变量吗?

Can I mutate a variable in place in a purely functional way?

我知道我可以使用状态传递和状态 monad 来实现纯功能性突变,但据我所知,这还不合适,我希望就地实现它的性能优势。

举个例子就好了,例如给数字加 1,最好是在 Idris 中,但 Scala 也不错

p.s。有突变标签吗?一个都看不到

不,这在 Scala 中是不可能的。

然而,在纯函数式语言中实现就地突变的性能优势是可能的。例如,让我们使用一个以纯函数方式更新数组的函数:

def update(arr: Array[Int], idx: Int, value: Int): Array[Int] =
  arr.take(idx) ++ Array(value) ++ arr.drop(idx + 1)

为了保持纯度,这里需要复制数组。原因是如果我们就地改变它,我们将能够在调用函数后观察到:

def update(arr: Array[Int], idx: Int, value: Int): Array[Int] = {
  arr(idx) = value
  arr
}

以下代码在第一个实现中可以正常工作,但在第二个实现中会中断:

val arr = Array(1, 2, 3)
assert(arr(1) == 2)
val arr2 = update(arr, 1, 42)
assert(arr2(1) == 42) // so far, so good…
assert(arr(1) == 2) // oh noes!

纯函数式语言的解决方案是简单地禁止最后一个断言。如果您无法观察到原始数组发生变异的事实,那么就地更新数组也没有错!实现这一点的方法称为线性类型。线性值是您可以 恰好一次 使用的值。将线性值传递给函数后,编译器将不允许您再次使用它,从而解决了问题。

我知道有两种语言具有此功能:ATS 和 Haskell。如果您想了解更多详细信息,我推荐 Simon Peyton-Jones 的演讲,他在 Haskell:

中解释了实现

https://youtu.be/t0mhvd3-60Y

对线性类型的支持已合并到 GHC 中:https://www.tweag.io/blog/2020-06-19-linear-types-merged/