我尝试了一些不同的方法,至少给出了部分答案。由于堆叠monad有时会出现问题,并且我们知道所有monad都是从某种数据类型构造的,所以我尝试组合数据类型。
我感觉更舒服 MonadFree 所以我使用它,但我想可以使用类似的方法 Operational 同样。
MonadFree
Operational
让我们从数据类型的定义开始:
{-# LANGUAGE DeriveFunctor, FlexibleContexts, FlexibleInstances, FunctionalDependencies #-} import Control.Monad import Control.Monad.Free data SLang x = ReadStr (String -> x) | WriteStr String x deriving Functor data ILang x = ReadInt (Int -> x) | WriteInt Int x deriving Functor
为了将两个仿函数组合在一起以在免费monad中使用它们,让我们定义它们的副产品:
data EitherF f g a = LeftF (f a) | RightF (g a) deriving Functor
如果我们创建一个免费的monad EitherF f g ,我们可以调用两个命令。为了使这个过程透明,我们可以使用 MPTC 允许从每个仿函数转换为目标仿函数:
EitherF f g
class Lift f g where lift :: f a -> g a instance Lift f f where lift = id instance Lift f (EitherF f g) where lift = LeftF instance Lift g (EitherF f g) where lift = RightF
现在我们可以打电话了 lift 并将任一部分转换为副产品。
lift
具有辅助功能
wrapLift :: (Functor g, Lift g f, MonadFree f m) => g a -> m a wrapLift = wrap . lift . fmap return
我们最终可以创建通用函数,允许我们从任何可以提升到仿函数的命令中调用命令:
readStr :: (Lift SLang f, MonadFree f m) => m String readStr = wrapLift $ ReadStr id writeStr :: (Lift SLang f, MonadFree f m) => String -> m () writeStr x = wrapLift $ WriteStr x () readInt :: (Lift ILang f, MonadFree f m) => m Int readInt = wrapLift $ ReadInt id writeInt :: (Lift ILang f, MonadFree f m) => Int -> m () writeInt x = wrapLift $ WriteInt x ()
然后,程序可以表示为
myProgram :: (Lift ILang f, Lift SLang f, MonadFree f m) => m () myProgram = do str <- readStr writeStr "Length of that str is" writeInt $ length str n <- readInt writeStr "you wanna have it n times; here we go:" writeStr $ replicate n 'H'
没有定义任何进一步的实例
虽然以上所有都很好用,但问题是如何一般地运行这样的组合免费monad。我不知道是否有可能拥有一个完全通用的,可组合的解决方案。
如果我们只有一个基本仿函数,我们就可以运行它
runSLang :: Free SLang x -> String -> (String, x) runSLang = f where f (Pure x) s = (s, x) f (Free (ReadStr g)) s = f (g s) s f (Free (WriteStr s' x)) _ = f x s'
如果我们有两个,我们需要线程化它们的状态:
runBoth :: Free (EitherF SLang ILang) a -> String -> Int -> ((String, Int), a) runBoth = f where f (Pure x) s i = ((s, i), x) f (Free (LeftF (ReadStr g))) s i = f (g s) s i f (Free (LeftF (WriteStr s' x))) _ i = f x s' i f (Free (RightF (ReadInt g))) s i = f (g i) s i f (Free (RightF (WriteInt i' x))) s _ = f x s i'
我想一种可能性就是表达运行仿函数 iter :: Functor f => (f a -> a) -> Free f a -> a 从 自由 然后创建一个类似的组合功能
iter :: Functor f => (f a -> a) -> Free f a -> a
iter2 :: (Functor f, Functor g) => (f a -> a) -> (g a -> a) -> Free (EitherF f g) a -> a
但我没有时间尝试一下。