Skip to content

Instantly share code, notes, and snippets.

@msiegenthaler
Created August 13, 2015 06:49
Show Gist options
  • Save msiegenthaler/bb00ac37a5057fe2c7c9 to your computer and use it in GitHub Desktop.
Save msiegenthaler/bb00ac37a5057fe2c7c9 to your computer and use it in GitHub Desktop.
Example for a free monad based console IO. Based upon http://underscore.io/blog/posts/2015/04/14/free-monads-are-simple.html.
import scalaz._
import scalaz.syntax.monad._
object Console {
import ConsoleOp._
def println(text: String): Console[Unit] = Free.liftFC(Println(text))
def readln: Console[String] = Free.liftFC(Readln())
//cannot use FreeC, because type inference for implicits will diverge
type Console[A] = Free[ConsoleF, A]
object ConsoleOp {
sealed trait ConsoleOp[+A]
case class Println(text: String) extends ConsoleOp[Unit]
case class Readln() extends ConsoleOp[String]
type ConsoleF[A] = Coyoneda[ConsoleOp, A]
}
}
/** Interpreter that reads from sysin and writes to sysout directly (side-effect). */
object ConsoleInterpreterSysout {
import Console.Console, Console.ConsoleOp._
def apply[A](f: Console[A]) = Free.runFC(f)(Transformation)
object Transformation extends (ConsoleOp ~> Id.Id) {
override def apply[A](fa: ConsoleOp[A]) = fa match {
case Println(text) => scala.Console.println(s"> $text")
case Readln() => scala.io.StdIn.readLine()
}
}
}
/** Interpreter that writes outputs to a list and takes input from another list. */
object ConsoleInterpreterLists {
import Console.Console, Console.ConsoleOp._
def apply[A](f: Console[A]) = Free.runFC(f)(Tranformation)
type Lists = (List[String], List[String])
type ListState[A] = State[Lists, A]
object Tranformation extends (ConsoleOp ~> ListState) {
override def apply[A](fa: ConsoleOp[A]) = fa match {
case Println(text) =>
for {
v <- State.get[Lists]
(ins, outs) = v
_ <- State.put((ins, outs :+ text))
} yield ()
case Readln() =>
for {
v <- State.get[Lists]
(ins, outs) = v
_ <- State.put((ins.tail, outs))
} yield ins.head
}
}
}
// Example use of the Console free monad
object Example2 {
import Console._
val program: Console[String] = {
for {
_ <- println("Please tell me your name (empty to exit):")
greeting = "Hello"
name <- readln
_ <- println(s"$greeting $name")
} yield name
}
def main(args: Array[String]): Unit = {
val res2 = ConsoleInterpreterLists(program.replicateM(2)).
run(("Maya" :: "Mario" :: Nil, Nil))
scala.Console.println(s"State results in ${res2._2} (outputs = ${res2._1._2})")
val res = ConsoleInterpreterSysout(program.iterateUntil(_.isEmpty))
scala.Console.println(s"Sysout results in $res")
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment