当我研究 Monod 时,我想知道什么途径最适合理解 Haskell 的 Monad。许多人如Bartosz Milewski建议Monads for functional programming是最好的 Material 。读完这篇论文的一部分后,我也有同样的感觉,但是在 4.2 Array transforms
中,我不知道如何理解关于 Monad 的总结,因为我错过了第 16 页底部的一些基础知识:
"将M做成抽象数据类型保证了单线程是
保留,因此使用就地更新实现赋值是安全的。
为此目的,数据抽象的使用是必不可少的。否则,一个人可以
编写违反单线程属性的程序,例如 (\x -> (assign i v x ; assign i w x ))
。”
不知道Philip Wadler为什么要在这里讨论单线程
? data M a = State -> (a, State)
对于保证单线程一定很重要,为什么?
为此,我实现了 4.2 数组转换
部分的代码,其中我假设我的数组类似于 Arr [("ok", 0), ("no", 1 )]
,index
为字符串,值为Int
:
type M a = State -> (a, State)
data Arr = Arr [(Id, Val)] deriving (Show)
type State = Arr
type Id = String
type Val = Int
type Ix = Id
update ix val arr = updateNew ix val arr (Arr [])
where updateNew ix val (Arr (x:xs)) (Arr newArr) =
case (fst x) == ix of
True -> Arr (newArr ++ ((ix,val):xs))
False -> updateNew ix val (Arr xs) (Arr (newArr ++ [x]))
assign :: Ix -> Val -> M ()
assign i v = \x -> ((), update i v x)
但这对我理解上面的总结没有帮助。希望有热心人士多多解释!
最佳答案
在 Haskell 中,[("ok", 0), ("no", 1)]
之类的东西不是数组*
,而是一个列表。 Haskell 列表是不可变的,所以你甚至不必考虑它们的变化。数组是另一回事。实际上有两种截然不同的东西,都称为数组:不可变数组和可变数组。
不可变数组只是某些类型的函数的替代表示以及有关它们域的一些信息。
Wadler 正在讨论实际上可以更改的可变数组。我们实际上并不直接处理这些数组;相反,我们处理作为指向它们的指针的值。在 ML、Java、C 等语言中,您可以随时“跟随”一个指针来访问或修改它指向的值。但这会完全破坏 Haskell 的引用透明性,而这对于理解和优化它都是至关重要的。
因此我们所做的是将对数组的更改封装在一个抽象的 monad 中。各种违反规则的事情都在幕后发生,但向你(程序员)展示的内容保证是有意义的。 GHC 中实际上有两个 monad 可以支持可变数组:IO
和 ST s
。 ST s
允许您在一个纯函数中创建一个数组,以各种方式对其进行变异,然后生成一个纯结果。另一方面,IO
允许您将数组创建和修改与其他 IO
操作混合。
*
在 GHC 中,它可能是一个数组,因为 GHC 提供了一个名为 OverloadedLists
的扩展,但即使在 GHC 中也不太可能是一个数组。
关于haskell - Monad和单线程有什么关系?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27893608/