为 RVarT 实现一个 MFunctor 实例

Implementing an MFunctor instance for RVarT

是否可以实施 MFunctor instance for RVarT

到目前为止,我已经得出以下结论:

{-# LANGUAGE RankNTypes #-}
import Data.RVar                        -- from rvar
import Control.Monad.Trans.Class (lift) -- from transformers

hoistRVarT :: Monad m => (forall t. n t -> m t) -> RVarT n a -> RVarT m a
hoistRVarT f rv = sampleRVarTWith (lift . f) rv

然而,由于 liftmMonad 约束,这不能用作 MFunctorhoist 的定义。问题是,如果没有 lift,我找不到另一种方法将生成的 monad 提升为 RVarT。但我认为从概念上讲它应该是可能的,因为 RVarT 应该类似于 StateT 并且 StateT 有一个 MFunctor 实例。问题是我在 rvarrandom-fu 的 API 中找不到任何公开此类功能的内容。

如果您不需要在没有 monad 实例的情况下实际使用值 RVarT m,我发现了一个适用于这种情况和类似情况的技巧 m。它的工作原理是推迟自然变换的应用,直到我们真正需要得到一个值。要是有合适的实例就好了

{-# LANGUAGE RankNTypes, ExistentialQuantification #-}

import Data.RVar
import Control.Monad.Trans.Class (lift)
import Control.Monad.Morph
import Control.Monad (ap)

hoistRVarT :: Monad m => (forall t. n t -> m t) -> RVarT n a -> RVarT m a
hoistRVarT f = sampleRVarTWith (lift . f)

data RVarTFun m a = forall n. RVarTFun 
  { transformation :: forall t. n t -> m t
  , rvart :: RVarT n a }

-- You can only get a value out if you have a monad for m.
getRVarTFun :: Monad m => RVarTFun m a -> RVarT m a
getRVarTFun (RVarTFun t ma) = hoistRVarT t ma

wrapRVarTFun :: RVarT m a -> RVarTFun m a
wrapRVarTFun = RVarTFun id

-- Actually the result is slightly stronger than MFunctor because we don't need
-- a Monad on n.
hoistRVarTFun :: (forall t. n t -> m t) -> RVarTFun n a -> RVarTFun m a
hoistRVarTFun f (RVarTFun t nx) = RVarTFun (f . t) nx

instance MFunctor RVarTFun where
  hoist = hoistRVarTFun

可以找到更通用的实现方式 here

RVarT m aPromptT Prim m anewtype,其中 PromptTControl.Monad.Prompt 中定义。 PromptT Prim m aPrompt (Lift Prim m) anewtype。这反过来又是 newtype for

forall b. (a -> b) -> (forall x. Lift Prim m x -> (x -> b) -> b) -> b

你可以用 unsafeCoerce:

解开整个东西
fromRVarT :: RVarT m a -> (a -> b) -> (forall x. Lift Prim m x -> (x -> b) -> b) -> b
fromRVarT = unsafeCoerce

toRVarT :: (forall b. (a -> b) -> (forall x. Lift Prim m x -> (x -> b) -> b) -> b) -> RVarT m a
toRVarT = unsafeCoerce

Prim 未导出,但由于您首先不需要触摸它,并且您正在使用 unsafeCoerce 组装和拆卸整个东西,您可以定义:

data Prim a

您可以为 Lift 编写一个 MFunctor 实例:

instance MFunctor (Lift f) where
  hoist _ (Effect p) = Effect p
  hoist phi (Lift m) = Lift (phi m)

然后你可以打开 RVarT,提升所有传递给它的提示函数的 Lift,然后再次包装它:

instance MFunctor RVarT where
  hoist phi rv = toRVarT $ \done prm -> fromRVarT rv done (\l -> prm $ hoist phi l)