【发布时间】:2016-04-25 12:34:13
【问题描述】:
我有一个名为 TaskMonad 的 Monad,定义如下:
data TaskMonad a = TaskMonad (Environment -> (TaskResult a, Environment))
其中Environment 是记录类型,TaskResult 是 ADT;但它们对问题并不重要。
我已经为TaskMonad 定义了Functor、Applicative 和Monad 实例,现在我希望能够将此单子与其他单子(例如IO)结合起来,所以我定义了一个新类型如下:
newtype Task m a = Task { runTask :: m (TaskMonad a) }
我已将Functor 和Applicative 定义如下:
instance Monad m => Functor (Task m) where
fmap f ta = Task $ do tma <- runTask ta
return (fmap f tma)
instance Monad m => Applicative (Task m) where
pure = Task . return . return
(<*>) prod tx = Task $ do tmprod <- runTask prod
tmtx <- runTask tx
return (tmprod <*> tmtx)
我还让Task 成为MonadTrans 类的成员:
instance MonadTrans Task where
lift = Task . (liftM return)
到目前为止一切顺利(或者至少可以编译..),但现在我想为Monad 定义实例,但我在这里遇到了问题:
instance Monad m => Monad (Task m) where
return = pure
(>>=) ta tb = ...
我尝试了很多事情,大多数尝试都是这样开始的:
(>>=) ta tb = Task $ do tma <- runTask ta
现在我们在 do 块中为 m monad 提供了 tma :: TaskMonad a。现在我想做的是,以某种方式调用>>= 实例为TaskMonad,这样我就可以得到tma 的结果,一个a 类型的值,所以我可以用它参数化tb 以获得一个Task b 的值。但是我在m monad 的上下文中,遇到了各种各样的问题。
我如何获得tma 的结果并提供给tb?
【问题讨论】:
-
一个明显的问题是你没有得到
Environment对吗?我认为你必须再次打开TaskMonad(而不是使用你已经得到的>>=) -
呃哦,说了很多坏话之后,我的 Applicative 实例让 TaskMonad 工作了。我生锈了现在正在尝试让您的绑定工作。
-
嗯,我想我将不得不稍微摆弄一下
Environment。需要注意的是TaskMonad的(>>=)函数有些复杂。仅仅向TaskMonad提供Environment是不够的。我需要使用TaskMonad的(>>=)来表达它。感谢您尝试 Bartek!我自己现在已经没有坏话了。 -
也许从一开始就将
TaskMonad定义为转换器?它在外观上看起来类似于 StateT,也许这是要走的路?
标签: haskell functional-programming monads monad-transformers