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

时间:2015-12-14 15:01:55

标签: arrays haskell immutability

我想要一个阵列,比如说:

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]

如何为可以更改值的值创建持有者。

谢谢!

1 个答案:

答案 0 :(得分:3)

所有Haskell值都是不可变的。您无法更改绑定到名称的值(您可以在GHCi中影子它们,但这有点不同)。

如果要实现真正的 1 可变性,则需要对可变数据进行不可变引用。要使用这些,通常您希望处于monadic环境中。

以下是使用名为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的值不会改变;它仍然指向相同的价值位置&#34;。指出的实际价值有何变化。

话虽这么说,但这需要使用通常不赞成的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 这有些含糊不清,但为了简单起见,我将其扩展为可以由直接内存操作支持的那个&#34;。