jak*_*ack 4 monads functional-programming scala
试图了解如何最好地应对FP中的副作用。
我实现了这个基本的IO实现:
trait IO[A] {
def run: A
}
object IO {
def unit[A](a: => A): IO[A] = new IO[A] { def run = a }
def loadFile(fileResourcePath: String) = IO.unit[List[String]]{
Source.fromResource(fileResourcePath).getLines.toList }
def printMessage(message: String) = IO.unit[Unit]{ println(message) }
def readLine(message:String) = IO.unit[String]{ StdIn.readLine() }
}
Run Code Online (Sandbox Code Playgroud)
我有以下用例:
- load lines from log file
- parse each line to BusinessType object
- process each BusinessType object
- print process result
Run Code Online (Sandbox Code Playgroud)
情况1:所以Scala代码可能看起来像这样
val load: String => List[String]
val parse: List[String] => List[BusinessType]
val process: List[BusinessType] => String
val output: String => Unit
Run Code Online (Sandbox Code Playgroud)
情况2:我决定在上面使用IO:
val load: String => IO[List[String]]
val parse: IO[List[String]] => List[BusinessType]
val process: List[BusinessType] => IO[Unit]
val output: IO[Unit] => Unit
Run Code Online (Sandbox Code Playgroud)
在情况1中,加载是不纯的,因为它是从文件中读取的,所以输出也是不纯的,因为它是将结果写入控制台。
为了更加实用,我使用了案例2。
问题:
- Aren't case 1 and 2 really the same thing?
- In case 2 aren't we just delaying the inevitable?
as the parse function will need to call the io.run
method and cause a side-effect?
- when they say "leave side-effects until the end of the world"
how does this apply to the example above? where is the
end of the world here?
Run Code Online (Sandbox Code Playgroud)
您的IO monad似乎缺少所有monad内容,即您可以flatMap通过它来从较小的IO中构建更大的IO的部分。这样,一切都将保持“纯净”,直到通话run结束为止。
如果不是第二种情况,我们是否只是延迟不可避免的事情?由于解析功能将需要调用io.run方法并引起副作用?
否。该parse函数不应调用io.run。它应该返回另一个IO,然后可以将其与其输入IO组合在一起。
当他们说“将副作用留到世界的尽头”时,这对上面的示例有何影响?世界的尽头在哪里?
世界末日将是您的程序要做的最后一件事。你只有run一次。程序的其余部分“纯粹”为此构建了一个巨型IO。
就像是
def load(): IO[Seq[String]]
def parse(data: Seq[String]): IO[Parsed] // returns IO, because has side-effects
def pureComputation(data: Parsed): Result // no side-effects, no need to use I/O
def output(data: Result): IO[Unit]
// combining effects is "pure", so the whole thing
// can be a `val` (or a `def` if it takes some input params)
val program: IO[Unit] = for {
data <- load() // use <- to "map" over IO
parsed <- parse()
result = pureComputation(parsed) // = instead of <-, no I/O here
_ <- output(result)
} yield ()
// only `run` at the end produces any effects
def main() {
program.run()
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
68 次 |
| 最近记录: |