Created
August 13, 2015 06:49
-
-
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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