我正在学习scalaz,现在我正在努力理解IOmonad 的观点.我读了这篇关于IO monads的文章,并尝试自己运行最简单的例子:
val io = println("test").pure[IO]
println("before")
io.unsafePerformIO()
Run Code Online (Sandbox Code Playgroud)
是的,它按预期工作.它打印
before
test
Run Code Online (Sandbox Code Playgroud)
但我无法抓住IO monad的要点.诀窍是什么?除了我所引用的文章中指定的"维护替代".
现在,这种替代似乎并不太有用.你能解释一下吗?
从我能想到的.想象一下,我有一些特质:
trait Reader{
def read(): List[Int]
}
trait Writer[T]{
def write(t: T): Unit
}
Run Code Online (Sandbox Code Playgroud)
所以我有一个能读取monadic值的读者(List在我的例子中).然后我需要在其他地方的容器中写入所有值,对它们执行一些转换.IO monad在这种情况下有用吗?
IO 就在我们身边,它使程序变得真正有用,因为我们不能整天计算纯表达式。
IO monad 试图解决使 IO 操作变得“不纯粹”的问题,例如从网络等不纯粹的来源获取数据。
IO 本身并不是引用透明的。考虑一个返回 的方法Unit,println例如。让我们尝试println仅替换Unit(或()),我们不会得到相同的值,不是吗?因为println有打印到控制台的效果。
使用你的例子,想象一下:
def write(t: T): Unit
Run Code Online (Sandbox Code Playgroud)
write如果我们替换为 会发生什么()?嗯,写入外部源会产生影响。然而,如果我们使用IO[Unit],我们就不会破坏替换。
要真正解决您的问题,我们需要将Listmonad 与IOmonad 结合起来,并且我们知道 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()
Run Code Online (Sandbox Code Playgroud)
这并不是很漂亮,而且可能不像调用一个有效的返回操作那么直接Unit,但我确信有比我在这里为了演示目的而创建的更好的方法来解决 monad 组合问题。
| 归档时间: |
|
| 查看次数: |
1701 次 |
| 最近记录: |