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

问题描述

我知道我可以将状态传递和状态 monad 用于纯粹的功能突变,但是 afaik 这不是就地的,我想要就地执行它的性能优势。

一个例子会很棒,例如给一个数加 1,最好在 Idris 中,但 Scala 也不错

附言有突变的标签吗?看不见

解决方法

不,这在 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],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/

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...