【发布时间】:2014-05-10 03:03:34
【问题描述】:
我一直在使用Haxl monad(在此描述:http://www.reddit.com/r/haskell/comments/1le4y5/the_haxl_project_at_facebook_slides_from_my_talk),它的 Applicative 实例的 <*> 与 Control.Monad 中的 ap 不同。这是一个关键特性,允许它在不阻塞的情况下进行并发计算。例如,如果hf 和ha 是长计算,那么
let hf :: Haxl (a -> b) = ...
ha :: Haxl a = ...
in do
f <- hf
a <- ha
return (f a)
将按顺序执行,而
hf <*> ha
将并行执行,然后合并结果。
我希望能够在 MaybeT Haxl 中运行计算,但问题是转换器包中 MaybeT m 的 Applicative 实例使用一元绑定:
instance (Functor m, Monad m) => Applicative (MaybeT m) where
pure = return
(<*>) = ap
ap = liftM2 id 来自Control.Monad。这使得
let hmf :: MaybeT Haxl (a -> b) = ...
hma :: MaybeT Haxl a = ...
in hmf <*> hma
按顺序运行。似乎更好的实例会更像
instance (Applicative m) => Applicative (MaybeT m) where
pure = MaybeT . pure . Just
MaybeT f <*> MaybeT x = MaybeT $ (<*>) <$> f <*> x
(这里,右侧的(<*>) 用于Maybe monad,而右侧不带括号的<*> 用于m。)注意上下文不同-- 上面的实例只假设Applicative m,而transformers中的实例假设Functor m, Monad m。
我的主要问题是实际的:我应该怎么做?我应该推出自己的MaybeT monad 变压器吗?如果我尝试编写上述内容,是否有某种方法可以解决 ghc 给我的“重复实例声明”投诉?
我也想知道:目前的设置是变压器包中的设计缺陷吗?如果没有,为什么不呢?
【问题讨论】:
-
每个人都倾向于假设超类实现完全匹配子类实现。 Haxl 违反了这条不成文的规则,因此无法与他人相处融洽。 Transformers 还假设您正在制作
Monad变压器,因此它的实现。Applicative“变形金刚”的结构要好得多。 -
@J.Abrahamson,这不是书面或其他规则。这也不是
<*>在某些重要方面优于ap的唯一情况。在我看来,MaybeT在这里是错误的。 -
AMP 作为 GHC 7.10 的一部分广泛传播后,我们可以重写
Applicative (MaybeT m)定义。目前Applicative不是Monad的超类,所以你可能会破坏很多包。我还惊讶地看到许多 Foo 是 Monad 的实例,但不是 Applicative 警告的实例。建议现在写你自己的MaybeT- 或者可能对transformers进行公关?。 -
@dfeuer 这往往是一条不成文的规则。人们经常假设您可以将 do 语法和
(<*>)语法切换为方便和漂亮的语法。一旦 AMP 落地,这将更加强大,但也可以很容易地用 Pplicative 切换这个定义。 -
其实这是一个书面规定——就在Control.Applicative documentation中
标签: haskell monads monad-transformers applicative haxl