Cats IO

Cats IO

Cats IO 是一种将 side effect 编码为纯值的数据类型,它能够描述同步和异步计算。 介绍 IO[A] 类型的值代表一种计算模型,在对它进行求值时,它将执行某种效果运算并返回 A 类型的值。 IO 的值是纯的,不变的,因此保留了引用透明性,因此被用于函数式编程。 IO 是一种数据结构,仅表示对副作用计算的描述。 IO 可以描述以下同步或异步计算: 只能得到唯一解。 可能以成功结束或以失败结束,并且在失败的情况下,flatMap 链会被短路(IO 实现了 MonadError 代数结构)。 可以取消,但请注意,此功能依赖用户提供取消逻辑。 由抽象的过程所描述的 effect 将不会被执行直到“世界的尽头”,具体地说,直到某个“unsafe”方法被调用为止。 效果的执行结果是不被记忆的,这意味着内存开销最小(并且没有泄漏),并且,单个 effect 可以被以“引用透明”的方式被多次执行。例如: 上面的这个的例子,“hey!”被打印了两次,因为这个 effect 在“单子”链中被重复地执行。 引用透明和惰性求值 IO 可以“冻结” side effect,因为它是一种惰性求值的数据类型。请参考以下分类并反复与标准库中的“Future”的进行比较,来理解求值模型(在 Scala 语境中)的全貌。   Eager Lazy Synchronous A () => A     Eval[A] Asynchronous (A => Unit) => Unit () => (A => Unit) => Unit   Future[A] IO[A] 通过与 Scala 的 Future 比较,IO 数据类型即使在处理副作用时也保留了引用透明性,并且它是惰性求值的。与像 Scala 这样的即时求值语言相比较,这是结果与产生结果的函数之间的区别。 与 Future 类似,通过 IO,您可以推断异步处理的结果,但是由于其纯性和惰性,可以将 IO 视为一个规范(直到“世界的尽头”才进行求值),从而可以对 IO 的求值模型施加更多的控制,并且更具可预测性。例如当组合多个 IO,或处理错误时,是以序列化的方式处理,还是以并行的方式处理。 注意惰性求值总是与引用透明性并存。参考以下示例: 如果我们考虑引用透明性,则可以将该示例重写为: 但是这不适用于 Future,但适用于 IO,此能力对于函数式编程至关重要。 堆栈安全 IO 在它的 flatMap 中是以 trampoline 的方式进行求值的,这意味着您可以在任意深度的递归函数中安全地调用 flatMap,而不必担心会顶爆堆栈: 根据 IO 中实现的类型类的层次结构。除某些函数外,所有这里定义的操作都可用于 IO。 Effects 介绍 IO 是一种强大的抽象,它可以效果化地描述多种不同的 effect: 纯值 — IO.pure & IO.unit 在 IO 的伴随类中定义了以下函数,可以用于将纯值加载到 IO 中,从而生成出“已经求值”的 IO 值: 请注意,给定的参数形式是值传递而不是按名(by-name)传递。 例如,我们可以将一个数字(纯值)放入 IO 中,然后将其安全地与另一个打包了side effect 的 IO 组合在一起,因为它们将不执行任何操作: 显然,IO.pure 无法挂起副作用,因为当参数被以值传递给它时,IO.pure 是即时求值的,因此请不要这样做: 在这种情况下,println 将触发副作用,该副作用不会在 IO 中被挂起,有鉴于此,这样的代码可能不是我们想要的。 IO.unit 是 IO.pure(()) 的简化的别名,可在需要 IO[Unit] 值时重复使用,而无需担心触发任何其他副作用: IO[Unit] 在 Scala 代码中使用的相当普遍,Unit 类型本身就意味着调用的返回有副作用,它可以作为 pure(()) 的快捷方式,并且可以起到优化的用处,因为返回了相同的引用。 同步效果 — IO.apply 它可能是最常用的构建器,等效于 Sync[IO].delay,描述了可以在当前线程和调用堆栈上立即做求值的 IO 操作: 请注意,给定的参数是通过“by-name”传递的,其执行被“暂停”在 IO 上下文中。 这个示例是在 JVM 之上使用阻塞 I/O 从控制台读取和写入信息: 然后,我们可以以纯函数的方式使用它们来对与控制台的交互进行建模: 异步 […]

BACK TO TOP