IO
You have imperative code that breaks referential transparency.
Wrap the imperative code with IO
, which can be
referenced safely without, and save the side effects for the last,
outermost layer of your program.
def multiplyM(x: Int, y: Int): Int = {
val z: Int = x * y
println(s"${x} * ${y} = ${z}")
z}
val zM: Int = {
multiplyM(6, 7) // prints "6 * 7 = 42"
multiplyM(6, 7) // prints "6 * 7 = 42"
multiplyM(6, 7) // prints "6 * 7 = 42"
} // zM = 42
IO
class IO[A](a: => A) {
def unsafePerformIO(): A = a
def map[B](f: A => B): IO[B] =
IO(f(a))
def flatMap[B](f: A => IO[B]): IO[B] =
IO(f(a).unsafePerformIO)
}
object IO {
def apply[A](a: => A): IO[A] =
new IO(a)
}
def multiplyI(x: Int, y: Int): IO[Int] =
[Int] {
IOval z: Int = x * y
println(s"${x} * ${y} = ${z}")
z}
val zI: IO[Int] = {
multiplyI(6, 7) // does not print anything
multiplyI(6, 7) // does not print anything
multiplyI(6, 7) // does not print anything
} // zI = IO[=> 42]
.unsafePerformIO // prints "6 * 7 = 42" zI
This file is literate Scala, and can be run using Codedown:
$ curl https://earldouglas.com/posts/itof/side-effects-to-io.md |
codedown scala |
xargs -0 scala -nc -e
6 * 7 = 42
6 * 7 = 42
6 * 7 = 42
6 * 7 = 42