为什么这个适用的实例是非法的?

Dmi*_*try 7 haskell applicative

我正在阅读有关monad变形金刚的文章,并发现这篇着名的文章 - "Monad变形金刚的温柔介绍".引起我注意的是作者描述临时ExceptT变压器的应用实例的部分,但留下了警告,提到该实例是非法的.

这是代码:

data EitherIO e a = EitherIO {
    runEitherIO :: IO (Either e a)
}

instance Functor (EitherIO e) where
    fmap f = EitherIO . fmap (fmap f) . runEitherIO

instance Applicative (EitherIO e) where
    pure    = EitherIO . return . Right
    f <*> x = EitherIO $
        liftA2 (<*>)
            (runEitherIO f)
            (runEitherIO x)
Run Code Online (Sandbox Code Playgroud)

警告:

警告:一位非常敏锐的读者向我指出,这个适用的例子是非法的.具体而言,它无条件地执行右侧的副作用.合法实例的期望是,如果左侧是成功的操作,它应该只执行右侧的副作用.

我假设具体实施<*>是问题.

所以我的主要问题是:这个例子确实不符合哪些法律?

从我所看到的,四个适用法律得到满足(当然我可能是错的).作者说,问题是右边的副作用(我假设,右边<*>)是执行的,即使左侧不是一个成功的操作(我假设,"成功操作"意味着IO动作Right在执行时会产生一个值).

虽然从使用的角度来看,我认为这是有道理的,但是看看哪些法律在这里不满意,以及为什么这样做仍然是有启发性的.

此外,对实例非法的原因的解释提到了副作用,这使得推理类型仅适用于IO monad?但是在文本的最后,作为一个结束动作,我们将IO monad更改为一般monad并使其成为所描述数据类型的参数.这引出了另一个问题:如果我们想象自己正在编写这个monad变换器,我需要应用什么样的推理,注意所描述的应用实例确实是非法的,而不需要考虑可能的特定monad用这个变压器?

luq*_*qui 6

这个Applicative例子是合法的.事实上,它与实例相同.应用仿函数的组合是适用的(这是应用程序具有monad所不具备的非常好的东西之一).ComposeIO (Either e)

但是,以下内容也列在文档的法律部分:

如果f也是Monad,它应该满足

pure = return
(<*>) = ap
(*>) = (>>)
Run Code Online (Sandbox Code Playgroud)

这就是问题所在,因为不存在与给定应用程序相对应的monad(这是关于RHS的条件执行的评论发挥作用的地方).所以这些ApplicativeMonad实例,虽然每个人都是合法的,但是不同意,这可以判处死刑.

  • 换句话说,[非]可交换的"Monad"应该是[非]可交换的"Applicative".(就个人而言,我认为这个要求是不必要的严格,我们应该以某种方式区分我们的意思是可交换的效果,但这是一个单独的问题.) (2认同)