这种签名发生了什么?(Haskell中的Vector.Mutable修饰符)

Jus*_* L. 10 haskell typeclass type-signature io-monad st-monad

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 ()
Run Code Online (Sandbox Code Playgroud)

现在我可以使用这些 -

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
Run Code Online (Sandbox Code Playgroud)

但是这里发生了什么?什么是PrimMonad?是PrimState一个构造函数?

我知道这里有一些绑定,在PrimMonad类monad上.thaw返回m (MVector (PrimState m) a),哪里mPrimMonad......但monad包含自己?为什么m在另一个的背景下m呢?

我看到一切基本上都与此有关,PrimState或者PrimMonad我看不出这与可变/可存储的向量有什么关系.那些允许它们存储状态的类型类有什么特别之处吗?

感谢您的时间!

Chr*_*icz 15

我认为你正在使用矢量包,如

import Data.Vector.Mutable
Run Code Online (Sandbox Code Playgroud)

PrimMonad类型类导致低级别的细节; 需要注意的是两个实例:

instance PrimMonad IO where ...
instance PrimMonad (ST s) where ...
Run Code Online (Sandbox Code Playgroud)

所以(PrimMonad m)只是一种说法mIO或者(ST s).这些是Haskell设置为允许你改变内存的两个基本monad.要清楚,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
Run Code Online (Sandbox Code Playgroud)

(PrimState m)代码中的类型取决于(PrimMonad m)分配给它的实例.

instance PrimMonad IO where
  type PrimState IO = RealWorld

instance PrimMonad (ST s) where
  type PrimState (ST s) = s
Run Code Online (Sandbox Code Playgroud)

RealWorld类型是GHC中IO的低级内部实现细节.s附加的类型(ST s)是存在类型的技巧,可以runST证明没有任何可变的东西逃脱了(ST s)monad.

要使相同的代码工作,IO(ST s)使用PrimMonad类型类(与关联PrimState)来提供临时重载.