所以我终于理解为什么Applicative对于表示并行执行非常有用,而Monads对于表示顺序执行非常有用。
话虽如此,我也明白Monads比Applicative更强大,所以我可以用ap
函数来表示bind
函数吗?
换句话说......我可以用Monads表示并行执行吗?
答案 0 :(得分:2)
The Monad
laws有话要说:
此外,Monad和Applicative操作应该相关 如下:
pure = return (<*>) = ap
鉴于ap
defined按顺序组成计算,
ap mf mx = do
f <- mf
x <- mx
return (f x)
只有一种方法可以阅读该法则:暴露monadic接口的类型不能使用Applicative
进行并行计算。您可以为monad提供newtype
包装器,该包装器具有并行Applicative
实例和 no Monad
实例,但您不能同时执行这两个操作
理论上,理论和实践是相同的,但在实践中,它们不是。在现实世界中,你确实看到人们弯曲这些规则并解释上述法则意味着(<*>)
应该道德等同于ap
,即使它不是完全等同于。
我知道的最好的例子恰好是直接解决你问题的那个例子。 Haxl是一个为并发IO实现特定于域的语言的库。 GenHaxl
monad <*>
会在可能的情况下自动并行两个计算,而>>=
按顺序运行它们(因为它必须)。这明显违背了法律的规定,但是由于Haxl用于数据库读取,它不会改变任何东西(而不是写,这样做)你有点可以逃脱它,世界不会爆炸。
答案 1 :(得分:1)
您可以<*>
和ap
实施Functor
,也可以Monad
:
class Functor m => Monad m where
join :: m (m a) -> m a
return :: a -> m a
(>>=) :: Monad m => m a -> (a -> m b) -> m b
m >>= f = join $ fmap f m
(<*>) :: Monad m => m (a -> b) -> m a -> m b
fs <*> xs = fs >>= \f -> xs >>= \x -> return (f x)
ap :: Monad m => m (a -> b) -> m a -> m b
ap = (<*>)
此示例隐藏了Haskell的标准Monad
定义,而是根据Monad
和join
定义return
,但您也可以定义{{1}来自join
;两种方式都有效。
答案 2 :(得分:0)
考虑一个案例:假设我们有两个期货。
jQuery_3_2_1("input[id^=DepartureDay]").on("change", function() {
alert("dd");
});
在上面的例子中,val future1 = Future {
//some long running computation
1
}
val future2 = Future {
// some othe long running computation
2
}
future1.flatMap(_ => future2)
和future1
并行运行,只要执行池中有足够的线程。
我们能够并行运行期货。那么,这是什么意思?
当前一个任务和当前任务(monad)之间存在数据依赖时,Monads会出现。但是,如果它们可以并行运行(至少在未来的情况下),则没有数据依赖性。
现在考虑一个案例:
future2
现在一个未来在其他人完成后运行。由于数据依赖性,现在执行必须是串行的。第二个未来取决于第一个未来的价值。