我有一件物品
object Producer {
def apply() :IO[Foo] = ???
}
字符串
我正在编写(平面Map)几个返回IO
的函数。其中一个隐藏了一个Ref
,并公开了与之兼容的update
方法:
object State {
def update(update: Bar => Bar) :IO[Bar] = ???
}
型
这一个我控制,虽然引入重大的变化将导致一个大的重构。
问题:
for {
bar <- State.update { arg => ??? }
} yield ()
型
在某些情况下,但不是所有情况下,我需要一个Foo
在传递给State.update
的lambda中生成一个新的Bar
。是否可以在不总是将foo <- Producer
作为第一步的情况下完成?
2条答案
按热度按时间0tdrvxhp1#
对
IO[A]
的一种思考方式是它是() => A
(或() => Future[A]
)。所以
() => IO[T]
和IO[() => T]
的想法是一样的,只是有不同的 * 人体工程学 *(和不同的方式来评估里面的东西)。所以你应该能够从一个进入另一个,然后返回,例如:字符串
然而,魔鬼在细节中:
runUnsafeSync
不会将取消从外部IO传播到内部IOIOLocal
中传播状态更新所以用这种方式进行防弹转换会相当困难
而且几乎从来没有它将是有用的,因为与人体工程学有一个公约:
IO[A]
表明有副作用(或至少有可能有副作用)X => non-IO
表示纯计算-取X
,然后返回sth,没有变化,也不与外部世界对话() =>
没有提供新的信息,所以这样的纯函数必须是常量(它可能基本上是一个惰性值)所以如果我们遵循惯例,我们可以通过执行以下操作将
fa: () => IO[A]
转换为IO[() => A]
型
这应该会使转换变得微不足道,但这也意味着所有这些
() =>
在IO[A]
的上下文中都是毫无意义的。除非你需要这样做来使你的代码适应一些需要() => F[A]
或F[() => A]
的外部接口,否则它只是噪音。tyu7yeag2#
你的问题是:我们能从
A => IO[B]
到IO[A => B]
吗?从概念上考虑一下。假设我们有一个函数
String => IO[Int]
,它接受用户名,从数据库中读取用户数据,并返回用户的年龄( Package 在IO
中,因为我们有一个数据库调用)。然后,您正在寻找一个高阶函数,它可以将name -> age函数转换为一个有效的值IO[String => Int]
。这怎么可能工作呢?String => Int
的实现可能是什么?以下两种情况都不存在:这是两个完全不同的东西。这里有一个关于它们区别的提示:
flatMap
接受一个A => F[B]
类型的函数,或者在你的例子中是A => IO[B]
。apply
接受一个F[A => B]
类型的函数,或者在你的例子中是IO[A => B]
。像你建议的那样使用for-comp是正确的方法。
字符串
或者写得不一样
型
它清楚地表明,状态更新取决于另一个函数,该函数指定了新的更新值。或者在我们前面的例子中-它表明您需要首先获得您的数字,然后才能将您的“三重”函数应用于它。
请注意,这里只讨论了操作的 * 顺序 * 或 * 依赖链 *。它没有说明它们在真实的世界中的实际执行情况;我们只是描述了懒惰的副作用程序的算法。(不像使用例如急切评估的
Future
,在这种情况下,您的关注将更加合理)你能解释一下这有什么问题吗?