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用这个变压器?
这个Applicative例子是合法的.事实上,它与实例相同.应用仿函数的组合是适用的(这是应用程序具有monad所不具备的非常好的东西之一).ComposeIO (Either e)
但是,以下内容也列在文档的法律部分:
如果
f也是Monad,它应该满足Run Code Online (Sandbox Code Playgroud)pure = return (<*>) = ap (*>) = (>>)
这就是问题所在,因为不存在与给定应用程序相对应的monad(这是关于RHS的条件执行的评论发挥作用的地方).所以这些Applicative和Monad实例,虽然每个人都是合法的,但是不同意,这可以判处死刑.