为 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
然而,由于 lift
对 m
的 Monad
约束,这不能用作 MFunctor
的 hoist
的定义。问题是,如果没有 lift
,我找不到另一种方法将生成的 monad 提升为 RVarT
。但我认为从概念上讲它应该是可能的,因为 RVarT
应该类似于 StateT
并且 StateT
有一个 MFunctor
实例。问题是我在 rvar
或 random-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 a
是 PromptT Prim m a
的 newtype
,其中 PromptT
在 Control.Monad.Prompt
中定义。 PromptT Prim m a
是 Prompt (Lift Prim m) a
的 newtype
。这反过来又是 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)
是否可以实施 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
然而,由于 lift
对 m
的 Monad
约束,这不能用作 MFunctor
的 hoist
的定义。问题是,如果没有 lift
,我找不到另一种方法将生成的 monad 提升为 RVarT
。但我认为从概念上讲它应该是可能的,因为 RVarT
应该类似于 StateT
并且 StateT
有一个 MFunctor
实例。问题是我在 rvar
或 random-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 a
是 PromptT Prim m a
的 newtype
,其中 PromptT
在 Control.Monad.Prompt
中定义。 PromptT Prim m a
是 Prompt (Lift Prim m) a
的 newtype
。这反过来又是 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)