这是我之前的 question 的后续内容。我从 Haxl 复制了下面的示例
假设我正在从博客服务器获取数据来呈现博客页面,其中包含最近的帖子、热门帖子和帖子主题。
我有以下数据获取 API:
val getRecent : Server => Seq[Post] = ...
val getPopular : Server => Seq[Post] = ...
val getTopics : Server => Seq[Topic] = ...
现在我需要组合它们来实现一个新功能 getPageData
val getPageData: Server => (Seq[Post], Seq[Post], Seq[Topic])
Haxl建议使用新的 monad Fetch
使 API 可组合。
val getRecent : Fetch[Seq[Posts]] = ...
val getPopular : Fetch[Seq[Posts]] = ...
val getTopics : Fetch[Seq[Topic]] = ...
现在我可以定义我的 getPageData: Fetch[A]
具有一元组合
val getPageData = for {
recent <- getRecent
popular <- getPopular
topics <- getTopics
} yield (recent, popular, topics)
但它不运行getRecent
, getPopular
,和getTopics
同时。
Haxl建议使用应用组合 <*>
组成“并发”函数(即可以同时运行的函数)。所以我的问题是:
- 如何实现
getPageData
假设Fetch[A]
是Applicative
? - 如何实现
Fetch
作为Applicative
但不是Monad
?
最佳答案
How to implement getPageData assuming Fetch[A] is an Applicative ?
我们需要做的就是删除单子(monad)绑定(bind) >>=
支持应用<*>
。所以而不是
val getPageData = for {
recent <- getRecent
popular <- getPopular
topics <- getTopics
} yield (recent, popular, topics)
我们会写一些类似的东西(用 Haskell 语法;抱歉,我无法立即使用 Scala):
getPageData = makeTriple <$> getRecent <*> getPopular <*> getTopics
where
makeTriple x y z = (x, y, z)
但是这是否能达到预期的效果还要看第二个问题!
How to implement Fetch as an Applicative but not a Monad ?
一元排序和应用排序之间的主要区别在于,一元排序可以依赖于一元值内的值,而应用 <*>
不能。请注意 getPageData
的一元表达式如何上面绑定(bind)了名称 recent
和popular
在到达getTopics
之前。这些名称可以用于更改表达式的结构,例如通过在 case recent
中获取其他数据源是空的。但使用applicative表达式,结果为getRecent
和getPopular
不是表达式本身结构中的因素。此属性允许我们同时触发应用表达式中的每个术语,因为我们静态地知道表达式的结构。
因此,利用上面的观察结果,以及 Fetch 数据类型的特定形状,我们可以为 <*>
给出一个合适的定义。 。我认为以下说明了总体思路:
data Fetch a = Fetch { runFetch :: IO a }
fetchF <*> fetchX = Fetch $ do
-- Fire off both IOs concurrently.
resultF <- async $ runFetch fetchF
resultX <- async $ runFetch fetchX
-- Wait for both results to be ready.
f <- wait resultF
x <- wait resultX
return $ f x
为了进行比较,假设我们尝试使用并发评估进行单子(monad)绑定(bind):
fetchF >>= fetchK = Fetch $ do
resultF <- async $ runFetch fetchF
-- Oh no, we need resultF in order to produce the next
-- Fetch value! We just have to wait...
f <- wait resultF
fetchX <- async $ runFetch (fetchK f)
x <- wait $ runFetch fetchX
return $ f x
关于scala - 如何使用Applicative实现并发?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27730707/