这是我之前提出的问题的跟进。下面的示例来自Haxl。
假设我从博客服务器获取数据以呈现博客页面,其中包含最近的文章、热门文章和文章主题。
我有以下数据获取API:
现在我需要将它们组合起来以实现一个新的功能
现在我可以使用单子组合来定义我的
假设我从博客服务器获取数据以呈现博客页面,其中包含最近的文章、热门文章和文章主题。
我有以下数据获取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建议使用applicative组合<*>
来组合“并发”函数(即可以同时运行的函数)。所以我的问题是:
- 如何实现
getPageData
,假设Fetch[A]
是一个Applicative
? - 如何将
Fetch
实现为Applicative
而不是Monad
?
Haskell
,所以才会问这个问题……你是将Fetch[A]
定义为一个记录,其中包含类型为IO[A]
的runFetch
字段吗? - Michael>>=
和<*>
定义。 - Alexander ViethHaxl
对Fetch
的定义有所不同,我会再读一遍,可能会在这里问更多问题。 - MichaelFetch
定义只是为了说明在应用程序中获取并发性背后的一般思想,而在单子中不可能实现。我相信Haxl的fetch更加复杂,因为它处理缓存。 - Alexander Vieth<*>
只是添加一个新节点。他们还有一个单独的“fetch”函数,它_解释_“Fetch”树并实际获取数据。fetch
处理所有缓存、批处理、异步等操作。 - Michael