【问题标题】:Defining PrimMonad instance for STT? (ST Transformer)为 STT 定义 PrimMonad 实例? (ST 变压器)
【发布时间】:2013-08-01 14:36:38
【问题描述】:

Data.Vector.Mutable 似乎需要ST sIO monad 中的PrimMonad 实例。

类型类被定义为这样--

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

【问题讨论】:

  • 您需要导入 the internal module 才能访问值构造函数。但是包裹的东西,(State# s -> m (STTRet s a)) 的类型错误。对于primitive/internal,您需要返回状态和结果的元组。对于某些单子m,您可以编写一个实例,但据我所知,您不能编写一个通用实例。
  • @DanielFischer 已导入;但我遇到了你提到的错误。有关如何使其适用于特定 monad 的任何提示?
  • 我认为没有办法解决您的问题。定义primitive 函数没有问题,但internal 函数即使对于简单的monad(例如writer monad 或reader monad)也是有问题的。无论如何,我一直无法提出解决方案。我认为您必须以某种方式概括 PrimMonad 才能实现您想做的事情。
  • @svenningsson 我该怎么做?
  • 我也在考虑编写自己的自定义组合 monad,但处理严格状态对我来说有点棘手

标签: haskell typeclass


【解决方案1】:

原则上,您可能能够为基元编写实现,但不能为内部编写实现,因为它为您的 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"

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-11-06
    • 1970-01-01
    • 1970-01-01
    • 2017-05-07
    • 1970-01-01
    • 2021-03-18
    • 2019-07-09
    相关资源
    最近更新 更多