15

执行定义的IO动作时,和动作someFun <$> (a :: IO ()) <$> (b :: IO ())的执行是否有序?也就是说,我可以指望那是在执行之前吗?abab

对于 GHC,我可以看到 IO 是使用 State 实现的,在这里也看到它是一个 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]

谢谢!

4

3 回答 3

18

这当然是确定性的,是的。对于任何特定实例,它总是会做同样的事情。但是,没有内在的理由选择从左到右而不是从右到左来选择效果顺序。

但是,从文档中Applicative

如果f也是 a Monad,它应该满足pure=return(<*>)= ap(这意味着满足应用函子定律)pure<*>

的定义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) }

这意味着,对于任何既是 a 又是 a 的函子MonadApplicative它是预期的(根据规范,因为这不能在代码中强制执行),Applicative它将从左到右工作,因此doliftM2做同样的事情liftA2 f x y = f <$> x <*> y

由于上述原因,即使对于Applicative没有相应 的实例Monad,按照惯例,效果通常也是从左到右排序的。

更广泛地说,因为计算的结构必须独立于“效果”,所以您通常可以独立于效果的排序Applicative方式来分析程序的含义。Applicative例如,如果将 for 的实例[]更改为从右到左的顺序,则任何使用它的代码都会给出相同的结果,只是列表元素的顺序不同。

于 2013-01-10T13:49:50.590 回答
4

是的,顺序是由 Monad-Applicative 对应预定义的。这很容易看出:(*>)组合子需要对应于一个单子(>>)行为良好的Applicative实例中的组合子,它的定义是:

a *> b = liftA2 (const id) a b

换句话说,如果b在 之前执行过aApplicative实例将表现不佳。

编辑:作为旁注:这没有在任何地方明确指定,但您可以找到许多其他类似的对应关系,例如liftM2=liftA2等。

于 2013-01-10T14:00:37.193 回答
2

对于 IO Applicative 来说,肯定是这样的。但是请查看async 包以获取 Applicative 的示例,其中f <$> a <*> b的效果ab并行发生。

于 2016-03-19T15:57:26.600 回答