13

我一直在使用Haxlmonad(在这里描述:http ://www.reddit.com/r/haskell/comments/1le4y5/the_haxl_project_at_facebook_slides_from_my_talk ),它有一个有趣的特性,<*>它的 Applicative 实例与apControl不同。单子。这是一个关键特性,允许它在不阻塞的情况下进行并发计算。例如,如果hfha是长计算,那么

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

(这里,(<*>)右侧是monad,而右侧Maybe未加括号的是。)请注意,上下文是不同的——上面的实例只假设,而转换器中的实例假设。<*>mApplicative mFunctor m, Monad m

我的主要问题是实际的:我应该怎么做?我应该推出自己的MaybeT单子变压器吗?如果我尝试编写上述内容,是否有某种方法可以解决 ghc 给我的“重复实例声明”投诉?

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

4

1 回答 1

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].

于 2014-03-31T05:34:52.037 回答