了解 Scala 中的 IO monad
Understanding IO monad in Scala
我正在学习 scalaz,现在我正试图理解 IO
monad 的要点。我阅读了 this article 关于 IO monads 的内容,并试图 运行 我自己的最简单的例子:
val io = println("test").pure[IO]
println("before")
io.unsafePerformIO()
是的,它按预期工作。它打印
before
test
但我无法理解 IO monad 的要点。诀窍是什么?除了我引用的文章中指定的 "maintains substitution" 。
这个替换现在对我来说似乎也不太有用。能解释一下吗?
据我所知。假设我有一些特征:
trait Reader{
def read(): List[Int]
}
trait Writer[T]{
def write(t: T): Unit
}
所以我有一个 reader 可以读取 monadic 值(List
在我的例子中)。然后我需要将容器中的所有值写入其他地方,对它们执行一些转换。 IO monad 在那种情况下有用吗?
IO 无处不在,它使程序真正有用,因为我们不能整天只计算纯表达式。
IO monad 试图解决进行 IO 操作的问题 "unpure",例如从网络等不纯来源获取数据。
IO 本身并不是引用透明的。考虑一个返回 Unit
的方法,例如 println
。让我们尝试用 println
代替 Unit
(或 ()
),我们不会得到相同的值,对吗?因为 println
具有打印到控制台的 效果 。
使用你的例子,想象一下:
def write(t: T): Unit
如果我们用 ()
替换 write
会发生什么?好吧,写入外部源会有效果。但是,如果我们使用 IO[Unit]
,我们就不会破坏替换。
要实际查看您的问题,我们需要将 List
monad 与 IO
monad 结合起来,而且我们知道 monad 不会组合。我们需要对 Monad Transformers 采取一些技巧:
import cats._
import cats.data.Nested
import cats.effect.IO
import cats.implicits._
val nested = Nested(IO.pure(reader.read()))
val res: Nested[IO, List, IO[Unit]] =
Functor[Nested[IO, List, ?]].map(nested)(i => writer.write(i))
val ioResult = for {
listOfIO <- res.value
flattened <- Applicative[IO].sequence(listOfIO)
} yield flattened
ioResult.unsafeRunSync()
这不是很漂亮,可能不像调用一个有效的操作返回 Unit
那样直接,但我确信有比我所用的更好的方法来绕过 monad 组合出于演示的目的而在此处创建。
我正在学习 scalaz,现在我正试图理解 IO
monad 的要点。我阅读了 this article 关于 IO monads 的内容,并试图 运行 我自己的最简单的例子:
val io = println("test").pure[IO]
println("before")
io.unsafePerformIO()
是的,它按预期工作。它打印
before
test
但我无法理解 IO monad 的要点。诀窍是什么?除了我引用的文章中指定的 "maintains substitution" 。
这个替换现在对我来说似乎也不太有用。能解释一下吗?
据我所知。假设我有一些特征:
trait Reader{
def read(): List[Int]
}
trait Writer[T]{
def write(t: T): Unit
}
所以我有一个 reader 可以读取 monadic 值(List
在我的例子中)。然后我需要将容器中的所有值写入其他地方,对它们执行一些转换。 IO monad 在那种情况下有用吗?
IO 无处不在,它使程序真正有用,因为我们不能整天只计算纯表达式。
IO monad 试图解决进行 IO 操作的问题 "unpure",例如从网络等不纯来源获取数据。
IO 本身并不是引用透明的。考虑一个返回 Unit
的方法,例如 println
。让我们尝试用 println
代替 Unit
(或 ()
),我们不会得到相同的值,对吗?因为 println
具有打印到控制台的 效果 。
使用你的例子,想象一下:
def write(t: T): Unit
如果我们用 ()
替换 write
会发生什么?好吧,写入外部源会有效果。但是,如果我们使用 IO[Unit]
,我们就不会破坏替换。
要实际查看您的问题,我们需要将 List
monad 与 IO
monad 结合起来,而且我们知道 monad 不会组合。我们需要对 Monad Transformers 采取一些技巧:
import cats._
import cats.data.Nested
import cats.effect.IO
import cats.implicits._
val nested = Nested(IO.pure(reader.read()))
val res: Nested[IO, List, IO[Unit]] =
Functor[Nested[IO, List, ?]].map(nested)(i => writer.write(i))
val ioResult = for {
listOfIO <- res.value
flattened <- Applicative[IO].sequence(listOfIO)
} yield flattened
ioResult.unsafeRunSync()
这不是很漂亮,可能不像调用一个有效的操作返回 Unit
那样直接,但我确信有比我所用的更好的方法来绕过 monad 组合出于演示的目的而在此处创建。