2014-03-30 54 views
13

我一直在使用Haxl monad(这里描述:http://www.reddit.com/r/haskell/comments/1le4y5/the_haxl_project_at_facebook_slides_from_my_talk),它有一个有趣的特性,<*>其应用实例与Control.Monad的ap不同。这是一个关键特性,可以在不阻塞的情况下进行并发计算。例如,如果hfha长计算,然后MaybeT m的应用实例假定Monad m

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

会做他们顺序地,而

hf <*> ha 

将并行做它们,然后合并结果。

我希望能够在MaybeT Haxl运行计算,但问题是,在变压器包MaybeT m应用型实例使用一元绑定:

instance (Functor m, Monad m) => Applicative (MaybeT m) where 
    pure = return 
    (<*>) = ap 

哪里ap = liftM2 idControl.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单子,而对非括号的右边是m<*>。)请注意,上下文不同 - 上述实例仅假设为Applicative m,而变换器中的实例假定为Functor m, Monad m

我的主要问题是实际的:我该怎么做呢?我应该推出我自己的MaybeT monad变压器吗?有没有办法避开ghc给我的“重复实例声明”的抱怨,如果我试着写上面的话?

我也想知道:目前的设置是否存在变压器封装的设计缺陷?如果不是,为什么不呢?

+6

每个人都倾向于认为超类实现完全匹配子类实现。哈克斯尔违反了这条不成文的规则,因此无法与其他人打好关系。变形金刚也假设你正在制造'Monad'变形金刚,因此它的实施。 'Applicative'“变形金刚”有更好的结构。 –

+0

@ J.Abrahamson,这不是一个规则,书面或其他。这也不是唯一的情况,其中'<*>'比'ap'更有效。在我看来'MaybeT'在这里是错误的。 – dfeuer

+0

After [AMP](https://www.haskell。org/haskellwiki/Functor-Applicative-Monad_Proposal)作为GHC 7.10的一部分广泛传播,我们可以重写'Applicative(MaybeT m)'定义。目前'Applicative'不是'Monad'的超类,所以你可能会破坏大量的包。我还看到很多* Foo是Monad的实例,但不是应用程序*警告。会建议现在写你自己的'MaybeT',或者可能做一个PR到'变形金刚'?. – phadej

回答

7

诀窍是(不像monad)应用函数是可组合的,所以你不需要(适用的)变换器,如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]产生。

+1

好的,很酷。但在这种情况下,我不能使用monad操作,对吧? (一般Haxl计算使用应用程序和monad来表示不同的数据流。)有什么方法可以获得两全其美的好处(即,一个HaxlM monad,ap!= <*>,而不需要从头开始编写)? – davidsd

+1

@davidsd我猜不。你也许可以使用'FlexibleInstances' /'FlexibleContexts'为'Compose Haxl Maybe'创建monad实例,但是最好从零开始创建'HaxlM' monad。 –

+2

只要我们走上这条道路,值得注意的是'Applicative'产品也是'Applicative'。只要有一个自然转变可以让偏见工作,那么与“Applicative”总和相同:http://comonad.com/reader/2012/abstracting-with-applicatives/ –

相关问题