如何在 Haskell 中保存列表可变值?

How to hold a list mutable values in Haskell?

我想要一个数组,比如:

myArray = [1,2,3,4,5,6,7,8,9]

并能够 运行 一个将列表中的值更改为另一个值的函数。我希望能够 运行 这个函数几次 myArray 在每次 运行.

之后更新到新的一组数字
myArray = [1,2,3,4,5,6,7,8,9]
>>> f 1 5 myAarray 
>>> myArray
[1,2,3,4,1,6,7,8,9]
>>> f 3 8 myArray
>>> myArray
[1,2,3,4,1,6,7,3,9]

如何为我的值创建一个可以更改值的容器。

谢谢!

所有 Haskell 值都是不可变的。您不能更改绑定到名称的值(您可以在 GHCi 中 shadow 它们,但这是一个稍微不同的事情)。

如果你想实现 true1 可变性,你需要一个不可变的 reference 到可变数据。要使用它们,通常您需要处于单子上下文中。

下面是一个使用名为 IORef:

的低级引用类型的示例
import Data.IORef
import Control.Monad

f :: [Int] -> [Int]
f = map (+1)

main = do
    a <- newIORef [1,2,3,4,5]
    readIORef a >>= print
    readIORef a >>= (return . f) >>= writeIORef a
    readIORef a >>= print

请注意,a 的值不会改变;它仍然指向相同的 "value location"。所指向的实际值发生了变化。


也就是说,这需要使用通常不受欢迎的 IO monad。根据您的需要,像 State 这样的完全纯净的解决方案可能会更好。

-- assume previous f
g :: State [Int] ()
g = modify f

现在你只需要从一些状态开始,状态 monad 会为你链接修改,就像这样:

main = print $ execState (g >> g >> g) [1,2,3,4,5]

这本质上等同于简单的组合:

f . f . f $ [1,2,3,4,5]

最后但同样重要的是,这可能是您在 Haskell 中的默认首选解决方案。


P.S。我在示例中使用了更简单的 f,但您没有理由不这样做:

(f 1 5) . (f 3 8) $ myArray

1这有点模棱两可,但为了简单起见,我将其扩展为 "the one that could be backed by direct memory operations"。