我正在尝试从renderTextxml-conduit monad一起获得ST。不幸的是,与renderBytes不同,它要求monad同时为PrimMonadMonadThrowIO满足此要求,但ST不满足。

renderText :: (PrimMonad m, MonadThrow m) => RenderSettings -> ConduitT Event Text m ()


通过定义PrimMonad实例,我设法使其与CatchT (ST s) a堆栈配合使用:

instance PrimMonad m => PrimMonad (CatchT m) where type PrimState (CatchT m) = PrimState m primitive = lift . primitive

这是不健康的孤立实例。我试图将其包装为newtype,但是卡在PrimMonad上。

newtype Render a = Render { runRender :: forall s. MaybeT (ST s) a }

instance Functor Render where
    fmap f (Render m) = Render (fmap f m)

instance Applicative Render where
    pure a = Render (pure a)
    (Render f) <*> (Render v) = Render (f <*> v)

instance Monad Render where
    a >>= f = Render $ do
        v <- runRender a
        runRender (f v)

instance MonadThrow Render where
    throwM _ = Render $ MaybeT $ pure Nothing

instance PrimMonad Render where
   [???]


如何为该堆栈定义PrimMonad

更新:记录下来,这是基于@luqui想法的答案。

newtype Render s a = Render { runRender :: MaybeT (ST s) a }

deriving instance Functor (Render s)
deriving instance Applicative (Render s)
deriving instance Monad (Render s)

instance MonadThrow (Render s) where
    throwM _ = Render $ MaybeT $ pure Nothing

instance PrimMonad (Render s) where
    type PrimState (Render s) = s
    primitive f = Render $ lift $ primitive f

最佳答案

您将需要公开s参数:

newtype Render s a = Render { runRender :: MaybeT (ST s) a }


forall s. ST s a monad看起来很吸引人,但它却毫无用处,因为newSTRef不能让它创建的引用逃脱。 (尝试使STRef与您的monad一起工作以查看问题)

公开s后,PrimMonad实例应该很简单。

您也知道GeneralizedNewtypeDeriving,对吗?您不必做所有这些工作就可以创建新类型的包装器。

10-08 12:35