我正在尝试从renderText
和xml-conduit
monad一起获得ST
。不幸的是,与renderBytes
不同,它要求monad同时为PrimMonad
和MonadThrow
。 IO
满足此要求,但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
,对吗?您不必做所有这些工作就可以创建新类型的包装器。