Data.Vector.Mutable
seems to require an instance of PrimMonad
in ST s
and IO
monads.
The typeclass is defined as this --
-- | Class of primitive state-transformer monads
class Monad m => PrimMonad m where
-- | State token type
type PrimState m
-- | Execute a primitive operation
primitive :: (State# (PrimState m) -> (# State# (PrimState m), a #)) -> m a
-- | Expose the internal structure of the monad
internal :: m a -> State# (PrimState m) -> (# State# (PrimState m), a #)
They're implemented like this --
instance PrimMonad IO where
type PrimState IO = RealWorld
primitive = IO
internal (IO p) = p
instance PrimMonad (ST s) where
type PrimState (ST s) = s
primitive = ST
internal (ST p) = p
I don't really understand at all what any of the functions of the typeclass are supposed to do, or how the implementations work.
But I need to implement it for STT (the one given by http://hackage.haskell.org/package/STMonadTrans-0.3.1)
STT
has constructor STT s m a
In my naive attempt I tried replacing everything ST s
with STT s m
:
instance Monad m => PrimMonad (STT s m) where
type PrimState (STT s m) = s
primitive = STT
internal (STT p m) = p
but I get this error:
Not in scope: data constructor `STT'
for the definitions of primitive
and internal
, despite having used STT
multiple times throughout the program already (although I guess as a type constructor?).
How should I properly implement this typeclass?
(I will eventually be using this as STT s (Rand g) a
)
EDIT: I imported Control.Monad.ST.Trans.Internal
to get STT
as a data constructor, and these are the new errors: (after changing internal (STT s m)
to internal (STT s)
)
Couldn't match kind `*' against `ArgKind'
Kind incompatibility when matching types:
m0 :: * -> *
(#,#) (ghc-prim:GHC.Prim.State# (PrimState (STT s m))) :: ArgKind
-> (#)
In the expression: STT
In an equation for `primitive': primitive = STT
Couldn't match type `m'
with `(#,#) (ghc-prim:GHC.Prim.State# (PrimState (STT s m)))'
`m' is a rigid type variable bound by
the instance declaration at src/pimc/PIMC.hs:41:16
Expected type: ghc-prim:GHC.Prim.State# (PrimState (STT s m))
-> (# ghc-prim:GHC.Prim.State# (PrimState (STT s m)), a #)
Actual type: ghc-prim:GHC.Prim.State# s -> m (STTRet s a)
In the expression: p
In an equation for `internal': internal (STT p) = p
Couldn't match type `a' with `STTRet s a'
`a' is a rigid type variable bound by
the type signature for
internal :: STT s m a
-> ghc-prim:GHC.Prim.State# (PrimState (STT s m))
-> (# ghc-prim:GHC.Prim.State# (PrimState (STT s m)), a #)
at src/pimc/PIMC.hs:44:3
Expected type: ghc-prim:GHC.Prim.State# (PrimState (STT s m))
-> (# ghc-prim:GHC.Prim.State# (PrimState (STT s m)), a #)
Actual type: ghc-prim:GHC.Prim.State# s -> m (STTRet s a)
In the expression: p
In an equation for `internal': internal (STT p) = p
Principally, you might be able to write an implementation for primitive, but not for internal, since it imposes a certain structure for your monad, which is only satisfied by the internal implementations of the IO and ST monads.
However, my impression is that the problem is with the Data.Vector.Mutable module, whose requirements are overly strict. To use for example an IO Vector in a monad m, you principally only need an embedding of IO into m (i.e. the primitive method) and not vice versa (i.e. the internal method). If this is correct, they should try to subdivide the PrimMonad class into an embedding part and an isomorphism part, for example as follows:
-- | Class of primitive state-transformer monads
class Monad m => PrimMonadEmbed m where
-- | State token type
type PrimState m
-- | Execute a primitive operation
primitive :: (State# (PrimState m) -> (# State# (PrimState m), a #)) -> m a
class PrimMonadEmbed m => PrimMonad m where
-- | Expose the internal structure of the monad
internal :: m a -> State# (PrimState m) -> (# State# (PrimState m), a #)
This might be okay in terms of backwards compatibility since no custom instances can exist in user code. Making the requirement less strict would also make their code usable with transformed versions of the IO monad like StateT Int IO etc.
You might try two things:
By the way, the following implementation of primitive should work (compare the source of STT to understand what went wrong in your code):
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UnboxedTuples #-}
module Test where
import Control.Monad.Primitive
import Control.Monad.ST.Trans
import Control.Monad.ST.Trans.Internal
instance Monad m => PrimMonad (STT s m) where
type PrimState (STT s m) = s
primitive f = STT (\s -> case (f s) of (# s', v #) -> return (STTRet s' v))
internal _ = error "no implementation of internal for STT"
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With