当我学习Monod时,我想知道什么路径最适合理解Haskell的Monad。许多人如Bartosz Milewski提出Monads for functional programming是最好的材料。在阅读了本文的一部分后,我得到了同样的感觉,但是在4.2 Array transforms
中,我不知道如何理解关于Monad的摘要,因为我错过了第16页底部的基础:
“将M转换为抽象数据类型可确保单个线程
保留,因此使用就地更新实现赋值是安全的。
数据抽象的使用对于此目的是必不可少的。否则,人们可以
编写违反单线程属性的(\x -> (assign i v x ; assign i w x ))
等程序。“
我不知道Philip Wadler为什么在这里讨论single threading
? data M a = State -> (a, State)
对于保证单线程必须非常重要,为什么?
为此,我实现了本节4.2 Array transforms
的代码,其中我假设我的数组与Arr [("ok", 0), ("no", 1)]
类似,而index
是字符串,值为Int
:< / p>
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)
但这对我理解上述摘要没有帮助。我希望有一个热情的人能够解释一下这个问题!
答案 0 :(得分:3)
在Haskell中,类似[("ok", 0), ("no", 1)]
的内容不数组*
,而是列表。 Haskell列表是不可变的,因此您甚至不必考虑它们的变化。数组是另一个故事。实际上有两个非常不同的东西,都叫做数组:不可变数组和可变数组。
不可变数组只是某些函数的替代表示,以及有关其域的一些信息。
Wadler正在讨论可变阵列,实际上可以更改。我们实际上并没有直接处理这些数组;相反,我们处理作为指针的值。在ML,Java,C等语言中,只要有人访问或修改指向的值,就可以“跟踪”指针。但这将彻底打破Haskell的引用透明度,这对理解和优化它至关重要。
因此,我们所做的是将更改封装到抽象monad中的数组中。各种各样的事情都在破坏规则的范围内进行,但程序员接触到的东西是有道理的。实际上有两个monad可以支持GHC中的可变数组:IO
和ST s
。 ST s
允许你在一个纯函数中创建一个数组,以各种方式改变它,然后产生一个纯粹的结果。另一方面,IO
允许您使用其他IO
操作混合数组创建和修改。
*
在GHC中,它可能是一个数组,因为GHC提供了一个名为OverloadedLists
的扩展,但即使在GHC中,它也很不太可能成为数组。