【问题标题】:Applicative instance for MaybeT m assumes Monad mMaybeT m 的应用实例假设 Monad m
【发布时间】: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 不同。这是一个关键特性,允许它在不阻塞的情况下进行并发计算。例如,如果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

(这里,右侧的(&lt;*&gt;) 用于Maybe monad,而右侧不带括号的&lt;*&gt; 用于m。)注意上下文不同-- 上面的实例只假设Applicative m,而transformers中的实例假设Functor m, Monad m

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

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

【问题讨论】:

  • 每个人都倾向于假设超类实现完全匹配子类实现。 Haxl 违反了这条不成文的规则,因此无法与他人相处融洽。 Transformers 还假设您正在制作Monad 变压器,因此它的实现。 Applicative“变形金刚”的结构要好得多。
  • @J.Abrahamson,这不是书面或其他规则。这也不是&lt;*&gt; 在某些重要方面优于ap 的唯一情况。在我看来,MaybeT 在这里是错误的。
  • AMP 作为 GHC 7.10 的一部分广泛传播后,我们可以重写 Applicative (MaybeT m) 定义。目前Applicative 不是Monad 的超类,所以你可能会破坏很多包。我还惊讶地看到许多 Foo 是 Monad 的实例,但不是 Applicative 警告的实例。建议现在写你自己的MaybeT - 或者可能对transformers 进行公关?。
  • @dfeuer 这往往是一条不成文的规则。人们经常假设您可以将 do 语法和(&lt;*&gt;) 语法切换为方便和漂亮的语法。一旦 AMP 落地,这将更加强大,但也可以很容易地用 Pplicative 切换这个定义。
  • 其实这是一个书面规定——就在Control.Applicative documentation

标签: haskell monads monad-transformers applicative haxl


【解决方案1】:

诀窍在于(与 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]

【讨论】:

  • 好的,很酷。但在这种情况下,我也不能使用 monad 操作,对吧? (一般的 Haxl 计算同时使用 applicative 和 monad 来表示不同的数据流。)有没有什么方法可以两全其美(即带有 ap != 的 HaxlM monad,无需从头开始编写)?跨度>
  • @davidsd 我猜没有。您也许可以使用FlexibleInstances/FlexibleContextsCompose Haxl Maybe 创建一个monad 实例,但最好还是从头开始创建HaxlM monad。
  • 只要我们在这条路上,值得注意的是Applicative产品也是Applicative。与Applicative sums 相同,只要有一个自然转换可以让偏差起作用:comonad.com/reader/2012/abstracting-with-applicatives
猜你喜欢
  • 1970-01-01
  • 2012-04-07
  • 1970-01-01
  • 1970-01-01
  • 2019-07-14
  • 2021-01-25
  • 2018-01-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多