MaybeT m的应用实例假设Monad m

时间:2014-03-30 21:48:58

标签: haskell monads monad-transformers applicative haxl

我一直在使用Haxl monad(此处描述:http://www.reddit.com/r/haskell/comments/1le4y5/the_haxl_project_at_facebook_slides_from_my_talk),其中有一个有趣的功能:<*>的Applicative实例与{{1}不同来自Control.Monad。这是一个关键功能,允许它在不阻塞的情况下进行并发计算。例如,如果aphf是长计算,那么

ha

将按顺序执行,而

let hf :: Haxl (a -> b) = ...
    ha :: Haxl a = ...
in do
  f <- hf
  a <- ha
  return (f a)

将并行执行,然后合并结果。

我希望能够在hf <*> ha 中运行计算,但问题是变换器包中的MaybeT Haxl的Applicative实例使用monadic bind:

MaybeT m

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 适用于(<*>) monad,而右侧的非括号Maybe适用于<*> 。)请注意,上下文不同 - 上面的实例仅假设为m,而变换器中的实例则假定为Applicative m

我的主要问题是实际问题:我该怎么做?我应该推出自己的Functor m, Monad m monad变压器吗?有没有办法绕过ghc给我的“重复实例声明”投诉,如果我试着写上面的?

我也想知道:当前的设置是变压器封装中的设计缺陷吗?如果没有,为什么不呢?

1 个答案:

答案 0 :(得分:7)

诀窍在于(与monads不同)应用函子是可组合的,因此您不需要(应用)变换器,例如MaybeT。相反,您可以使用Compose将两个应用函子组合在一起:

import Control.Applicative
import Data.Functor.Compose

type HaxlM = Compose Haxl Maybe

-- if you prefer to have a function for constructing values:
haxlM :: Haxl (Maybe a) -> HaxlM a
haxlM = Compose

组合始终是Applicative的正确实例,并且仅使用其组件的Applicative实例。例如:

test = getZipList . getCompose
       $ (+) <$> Compose (ZipList [Just 1,  Nothing, Just 3])
             <*> Compose (ZipList [Nothing, Just 20, Just 30])

生成[Nothing,Nothing,Just 33]