执行someFun <$> (a :: IO ()) <$> (b :: IO ())
定义的IO操作时,是否执行了a
和b
操作?也就是说,我可以指望在a
之前执行b
吗?
对于GHC,我可以看到IO是使用State实现的,并且还看到here它是一个Applicative实例,但是找不到实际实例声明的来源。通过State实施表明,不同的IO效应需要是连续的,但没有必要定义它们的顺序。
在GHCi中玩,似乎Appliative保留了效果顺序,但这是一些普遍的保证,还是GHC特定的?我会对细节感兴趣。
import System.Time
import Control.Concurrent
import Data.Traversable
let prec (TOD a b) = b
fmap (map prec) (sequenceA $ replicate 5 (threadDelay 1000 >> getClockTime))
[641934000000,642934000000,643934000000,644934000000,645934000000]
谢谢!
答案 0 :(得分:18)
肯定是确定性,是的。对于任何特定实例,它总是会做同样的事情。但是,没有固有的理由从右到左选择从左到右的效果顺序。
但是,来自the documentation for Applicative
:
如果
f
也是Monad
,则应该满足pure
=return
和(<*>)
=ap
(这意味着pure
1}}和<*>
满足应用仿函数法则)。
ap
的定义来自Control.Monad
:
ap :: (Monad m) => m (a -> b) -> m a -> m b
ap = liftM2 id
liftM2
以明显的方式定义:
liftM2 f m1 m2 = do { x1 <- m1; x2 <- m2; return (f x1 x2) }
这意味着,对于Monad
以及Applicative
的任何算符,预期(按规范,因为这不能在代码中强制执行), Applicative
将从左到右工作,因此do
中的liftM2
阻止与liftA2 f x y = f <$> x <*> y
的功能相同。
由于上述原因,即使对于没有相应Applicative
的{{1}}个实例,按照惯例,效果通常也是从左到右排序。
更广泛地说,因为Monad
计算的结构必然与“效果”无关,所以通常可以独立于Applicative
效果的排序方式来分析程序的含义。例如,如果Applicative
的实例从右到左更改为序列,则使用它的任何代码都会给出相同的结果,只是列表元素的顺序不同。
答案 1 :(得分:4)
是的,订单是由Monad-Applicative通信预先定义的。这很容易看出:(*>)
组合子需要与monad中行为良好的(>>)
实例中的Applicative
组合子对应,其定义为:
a *> b = liftA2 (const id) a b
换句话说,如果在b
之前执行了a
,则Applicative
实例将会出现问题。
编辑:作为旁注:这并未在任何地方明确指定,但您可以找到许多其他类似的对应关系,例如liftM2
= liftA2
等。
答案 2 :(得分:2)
对于IO Applicative,情况确实如此。但请查看async package以获取应用的示例,其中['http://www.playhd.video/embed.php?vid=621',
'http://mersalaayitten.com/embed/3752',
'http://www.playhd.video/embed.php?vid=584',
'http://googleplay.tv/videos/kanithan?iframe=true']
f <$> a <*> b
和a
的影响并行发生。