Реализация PrimMonad для стека CatchT (ST) нового типа-d

Я пытаюсь получить renderText от xml-conduit работать с ST монада. К сожалению, в отличие от renderBytesМонада должна быть PrimMonad а также MonadThrow, IO удовлетворяет это, но ST не делает.

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

Мне удалось заставить его работать с CatchT (ST s) a стек, определяя экземпляр PrimMonad:

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

Это нездоровый сиротский экземпляр. Я пытался обернуть его в новый тип, но застрял на 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 для этого стека?

1 ответ

Решение

Вам нужно будет выставить s параметр:

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

forall s. ST s a Монада выглядит привлекательно, но это довольно бесполезно, так как (например) newSTRef не могу позволить рефери, которую он создал, сбежать. (Попробуйте сделать STRef s работать с вашей монадой, чтобы увидеть проблему)

Как только вы выставляете s PrimMonad экземпляр должен быть простым.

Также вы знаете о GeneralizedNewtypeDeriving, право? Вам не нужно делать всю эту работу, чтобы сделать упаковщик нового типа.

Другие вопросы по тегам