我正在阅读此博客post,声称Futures
不是“功能性”,因为它们只是副作用计算的包装。例如,它们包含RPC调用,HTTP请求等。它是否正确?
博客文章给出了以下示例:
def twoUsersFeed(a: UserHandle, b: UserHandle)
(implicit ec: ExecutionContext): Future[Html] =
for {
feedA <- usersFeed(a)
feedB <- usersFeed(b)
} yield feedA ++ feedB
you lose the desired property: consistent results (the referential transparency). Also you lose the property of making as few requests as possible. It is difficult to use multi-valued requests and have composable code.
恐怕我没理解。你能解释一下我们在这种情况下如何失去consistent result
吗?
答案 0 :(得分:11)
博客文章无法区分Future
本身及其常用方式,IMO。你可以编写带有Future
的纯函数代码,如果你只编写了Future
s,称为纯函数;这样的代码在每个远程合理的意义上都是引用透明和“功能性的”。
真实的是,Future
s可以限制对副作用的控制,如果你将它们与有副作用的方法一起使用。如果您创建Future
包裹webClient.get
,则创建Future
将发送HTTP呼叫。但这不是关于Future
的事实,这是关于webClient.get
的事实!
这篇博客文章中有一点道理。通过例如完全分离表达您的计算与执行它免费monad,可以产生更高效,更可测试的代码。例如。您可以创建一个“查询语言”,在这里您可以表达“获取A和B的所有共同朋友的个人资料照片”而不实际运行它的操作。这样可以更容易地测试您的逻辑是否正确(因为它很容易制作,例如可以“运行”相同查询的测试实现 - 甚至只是直接检查“查询对象”),并且,我认为博客文章试图建议,意味着你可以,例如组合多个请求以获取相同的配置文件。 (这甚至不是纯粹的功能编程问题 - 一些OO书籍有一个“命令模式”的想法 - 尽管IME函数编程工具如for
/ yield
语法使工作更容易通过这种方式)。然而,如果您拥有的是fetchProfile
方法,则在运行时立即触发HTTP请求,然后如果您的代码逻辑请求两次相同的配置文件,则无法避免两次获取相同的配置文件。
但这本身并不是Future
本身,IMO这篇博文更令人困惑而不是有用。