为STT定义PrimMonad实例? (ST变压器)

时间:2013-07-08 08:36:33

标签: haskell typeclass

Data.Vector.Mutable似乎需要PrimMonadST s monad中的IO个实例。

类型类定义为 -

-- | 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 #)

他们是这样实施的 -

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

我根本不了解类型类的任何功能应该做什么,或者实现如何工作。

但是我需要为STT(由http://hackage.haskell.org/package/STMonadTrans-0.3.1给出的那个)

实现它

STT有构造函数STT s m a

在我天真的尝试中,我尝试用ST s替换所有STT s m

instance Monad m => PrimMonad (STT s m) where
  type PrimState (STT s m) = s
  primitive = STT
  internal (STT p m) = p

但是我收到了这个错误:

Not in scope: data constructor `STT'

关于primitiveinternal的定义,尽管已经在整个程序中多次使用STT(虽然我猜是一种类型构造函数?)。

我该如何正确实现这个类型类?

(我最终会将其用作STT s (Rand g) a


编辑:我导入Control.Monad.ST.Trans.Internal以获取STT作为数据构造函数,这些是新错误:(在将internal (STT s m)更改为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

1 个答案:

答案 0 :(得分:3)

主要是,您可能能够为原语编写实现,但不能为内部编写实现,因为它为monad强加了某种结构,只有IO和ST monad的内部实现才能满足。

但是,我的印象是问题出在Data.Vector.Mutable模块上,其要求过于严格。例如,在monad m中使用IO向量,主要只需要将IO嵌入到m(即原始方法)中,而不是反之亦然(即内部方法)。如果这是正确的,他们应该尝试将PrimMonad类细分为嵌入部分和同构部分,例如如下:

-- | 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 #)

这在向后兼容性方面可能没问题,因为用户代码中不存在自定义实例。使要求不那么严格也会使它们的代码可用于转换版本的IO monad,如StateT Int IO等。

您可以尝试两件事:

  • 为PrimMonad实现一个部分实例,它只实现了原始方法并使内部抛出错误,看看你是否可以像这样使用矢量库
  • 联系您正在使用的矢量库的作者,并询问他们上述提案是否切合实际......

顺便说一下,原语的以下实现应该有效(比较STT的来源以了解你的代码中出了什么问题):

{-# 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"