gpt4 book ai didi

scala - 如何使用Applicative实现并发?

转载 作者:行者123 更新时间:2023-12-02 18:06:03 26 4
gpt4 key购买 nike

这是我之前的 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)了名称 recentpopular在到达getTopics之前。这些名称​​可以用于更改表达式的结构,例如通过在 case recent 中获取其他数据源是空的。但使用applicative表达式,结果为getRecentgetPopular不是表达式本身结构中的因素。此属性允许我们同时触发应用表达式中的每个术语,因为我们静态地知道表达式的结构。

因此,利用上面的观察结果,以及 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/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com