Haskell中的可变载体有三个元素级突变子:
read :: PrimMonad m => MVector (PrimState m) a -> Int -> m a
write :: PrimMonad m => MVector (PrimState m) a -> Int -> a -> m ()
swap :: PrimMonad m => MVector (PrimState m) a -> Int -> Int -> m ()
现在我可以使用这些精细的
import Data.Vector
import Data.Vector.Mutable
import Control.Monad.ST
import Control.Monad.Primitive
incrAt :: Vector Double -> Int -> Vector Double
incrAt vec i = runST $ do
mvec <- thaw vec
oldval <- read mvec i
write mvec i (oldval + 1)
freeze mvec
但是这里发生了什么?什么是PrimMonad
?PrimState
是构造函数吗?
我知道这里有一些绑定,在PrimMonad
类monad上。thaw
返回m (MVector (PrimState m) a)
,其中m
是PrimMonad
。。。但是monad包含它自己?为什么m
在另一个m
的上下文中?
我看到所有东西基本上都绑定在这个PrimState
或PrimMonad
上,但我不明白这与可变/可存储向量有什么关系。这些类型类有什么特别的地方可以存储状态吗?
感谢您抽出时间!
我认为您使用的是矢量包,如
import Data.Vector.Mutable
遵循PrimMonad
类型类会导致低级别的详细信息;需要注意的是以下两个例子:
instance PrimMonad IO where ...
instance PrimMonad (ST s) where ...
所以(PrimMonad m)
只是说m
是IO
或(ST s)
的一种方式。这是两个基本的monad,Haskell在其中被设置为允许您改变内存。需要明确的是,m
是一个类型构造函数,将m
应用于类似Int
的类型会得到一个类型:m Int
。
需要强调的是:IO
和(ST s)
是特别的,因为它们允许您使用这种能力来"存储状态",从而改变实际内存。它们以Haskell的其他部分隐藏的原始形式公开了这种功能。
现在PrimState是一个新事物:一个关联的数据类型。在PrimMonad
类型类中有一个声明:
-- | Class of primitive state-transformer monads
class Monad m => PrimMonad m where
-- | State token type
type PrimState m
(PrimState m)
在代码中的类型取决于分配给它的(PrimMonad m)
的实例
instance PrimMonad IO where
type PrimState IO = RealWorld
instance PrimMonad (ST s) where
type PrimState (ST s) = s
RealWorld
类型是GHC中IO的低级别内部实现细节。附加到(ST s)
的s
类型是存在类型技巧,它让runST
证明没有任何可变的东西逃脱了(ST s)
monad。
为了使相同的代码在IO
和(ST s)
中工作,PrimMonad
类型类(具有相关联的PrimState
)用于提供自组织重载。