Skip to content

Instantly share code, notes, and snippets.

@msiegenthaler
Last active November 6, 2015 15:53
Show Gist options
  • Save msiegenthaler/a5d8a2db7cedd0fd6b93 to your computer and use it in GitHub Desktop.
Save msiegenthaler/a5d8a2db7cedd0fd6b93 to your computer and use it in GitHub Desktop.
package example2
import cats.std.list._
import cats.std.function._
import cats.syntax.foldable._
import cats.state.State
import cats._
import cats.free._
object Console {
import Op._
type Console[A] = Free[ConsoleOp, A]
implicit val monad = Free.freeMonad[ConsoleOp]
def readln: Console[String] = Free.liftF(Readln())
def println(text: String): Console[Unit] = Free.liftF(Println(text))
object Op {
sealed trait ConsoleOp[+A]
case class Println(text: String) extends ConsoleOp[Unit]
case class Readln() extends ConsoleOp[String]
}
}
/** Interpreter that reads from sysin and writes to sysout directly (side-effect). */
object ConsoleInterpreterSysout {
import Console.Console, Console.Op._
def apply[A](f: Console[A]) = f.foldMap(Compiler)
object Compiler extends (ConsoleOp ~> Id) {
override def apply[A](fa: ConsoleOp[A]): Id[A] = fa match {
case Println(text) ⇒ scala.Console.println(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.Op._
def apply[A](f: Console[A]): ListState[A] = f.foldMap(Compiler)
type Lists = (List[String], List[String])
type ListState[A] = State[Lists, A]
object Compiler extends (ConsoleOp ~> ListState) {
override def apply[A](fa: ConsoleOp[A]): ListState[A] = fa match {
case Println(text) ⇒
for {
v ← State.get[Lists]
(ins, outs) = v
_ ← State.set((ins, outs :+ text))
} yield ()
case Readln() ⇒
for {
v ← State.get[Lists]
(ins, outs) = v
_ ← State.set((ins.tail, outs))
} yield (ins.head)
}
}
}
// Example use of the Console2 free monad
object Example {
import Console._
import scala.language.higherKinds
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 repeat[M[_] : Monad](times: Int)(fa: M[_]) = List.fill(times)(fa).sequence_
def iterateUntil[M[_] : Monad, A](pred: A ⇒ Boolean)(fa: M[A]): M[A] =
Monad[M].flatMap(fa)(y ⇒ if (pred(y)) Monad[M].pure(y) else iterateUntil(pred)(fa))
def main(args: Array[String]): Unit = {
val res2 = ConsoleInterpreterLists(repeat(2)(program)).
run(("Maya" :: "Mario" :: Nil, Nil)).run
scala.Console.println(s"State results in ${res2._2} (outputs = ${res2._1._2})")
val res = ConsoleInterpreterSysout(iterateUntil((v: String) ⇒ v.isEmpty)(program))
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