IO Monad
The content of this chapter is available as a Scala file here.
trait IOMonad {
type IO[_]
def unit[A](a: A): IO[A]
def bind[A, B](m: IO[A], f: A => IO[B]): IO[B]
def printString(s: String): IO[Unit]
def inputString: IO[String]
def performIO[A](action: IO[A]): A
}
val iomonad: IOMonad = new IOMonad {
type World = String
type IO[A] = World => (A, World)
def unit[A](a: A): IO[A] = w => (a, w)
def bind[A, B](m: IO[A], f: A => IO[B]): IO[B] =
w => m(w) match { case (a, w2) => f(a)(w2) }
def printString(s: String): IO[Unit] =
w => { println(s); ((), w + s + " was printed and then ...\n") }
def inputString: IO[String] =
w => {
val input = scala.io.StdIn.readLine();
(input, w + input + " was entered and then ...\n")
}
def performIO[A](action: IO[A]): A =
action("The world in which nothing has happened yet, but then ...\n") match {
case (a, w) =>
println("Peformed all actions. The world in which all this happened is: \n" + w); a
}
}
def someIOActions(implicit m: IOMonad): m.IO[Unit] =
m.bind(m.printString("Enter your first name:"), (_: Unit) =>
m.bind(m.inputString, (firstName: String) =>
m.bind(m.printString("Enter your last name:"), (_: Unit) =>
m.bind(m.inputString, (lastName: String) =>
m.printString("Hello, " + firstName + " " + lastName + "!")))))
def test = iomonad.performIO(someIOActions(iomonad))