正如@ user2407038指出的那样,首先将自己限制在一个具体的MVector
类型如IOVector
更容易。如果你擅长的new
,read
和write
到IOVector
类型,您会收到以下方式中,特别是非恐吓类型:
new :: Int -> IO (IOVector a)
read :: IOVector a -> Int -> IO a
write :: IOVector a -> Int -> a -> IO()
所以对于第一个版本,你Matrix
操作的实现是直截了当:
import Data.Vector.Mutable as V
import Control.Monad (liftM)
data Matrix a = Matrix { size :: (Int, Int), buffer :: IOVector a }
newMatrix :: (Int, Int) -> IO (Matrix a)
newMatrix (w, h) = liftM (Matrix (w, h)) $ V.new (w * h)
set :: (Int, Int) -> a -> Matrix a -> IO()
set pos e mtx = V.write (buffer mtx) (offset mtx pos) e
get :: (Int, Int) -> Matrix a -> IO a
get pos mtx = V.read (buffer mtx) (offset mtx pos)
offset :: Matrix a -> (Int, Int) -> Int
offset (Matrix (w, _h) _) (x, y) = w * y + x
那么,我们如何推广MVector s
中的s
? Matrix
本身需要一概而论超过s
选择:
data Matrix s a = Matrix { size :: (Int, Int), buffer :: MVector s a }
而且我们还需要通过线程这个推广到所有的功能。我们来看看newMatrix
的细节;其余的可以留给读者作为练习。
如果我们只是抽象的s
,newMatrix
成为
newMatrix :: (Int, Int) -> IO (Matrix s a)
newMatrix (w, h) = liftM (Matrix (w, h)) $ V.new (w * h) -- Same implementation as above
但是,这肯定不可能是正确的 - 我们不能为s
任何选择,只有RealWorld
创建IO
MVector s a
!果然,在typechecker抓住这样的:
Couldn't match type `s' with `RealWorld'
`s' is a rigid type variable bound by
the type signature for newMatrix :: (Int, Int) -> IO (Matrix s a)
Expected type: s
Actual type: PrimState IO
Expected type: IO (MVector s a)
Actual type: IO (MVector (PrimState IO) a)
In the return type of a call of `new'
In the second argument of `($)', namely `new (w * h)'
但假设我们写
newMatrix :: (Monad m) => (Int, Int) -> m (Matrix s a)
这一点,在某种意义上说,更糟糕的是,现在我们是在说为m
和s
任何选择(独立的彼此!),我们可以在m
中构建Matrix s a
。显然情况并非如此。
这是需要的PrimMonad
类型类,其中:它提供PrimState m
之间的联系,的s
为向量选择被操纵,并且单子m
其中该操作是可能的。 newMatrix
从而成为
newMatrix :: (PrimMonad m) => (Int, Int) -> m (Matrix (PrimState m) a)
newMatrix (w, h) = liftM (Matrix (w, h)) $ V.new (w * h) -- implementation is still the same!
其它操作可以以类似的方式被键入。
'newMatrix'将不得不具有'(PrimMonad m,MVector va)=> arg1 - > arg2 - > argN - > m(Matrix vsa)'类型',因为您需要使用'Data。 Vector.Generic.Mutable.new'来构造它。 – bheklilr
'PrimState'是一个与'PrimMonad'关联的类型。只有两个'PrimMonad'实例:'ST s'和'IO'。因此'PrimState'或者是'RealWorld'或's'(来自'STs')。但是这些东西隐藏在['Control.Monad.Primitive']中(http://hackage.haskell.org/package/primitive-0.2.1/docs/Control-Monad-Primitive.html#t:PrimMonad)。 – Zeta
注意:您链接的文档很古老。这是2010年的“矢量0.5”。看看['vector 0.10.12。*'](http://hackage.haskell.org/package/vector-0.10.12.2/docs/Data-Vector-Mutable.html ),相反,虽然类型仍然大体相同。 – Zeta