Last active
March 15, 2018 03:39
-
-
Save chenharryhua/a4d14896b2a26b30fe85e8d2cac143b1 to your computer and use it in GitHub Desktop.
type checked. but runtime error: java.lang.ClassCastException: scala.runtime.BoxedUnit cannot be cast to scalaz.Free
This file contains 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
package cofreecomonad | |
import scalaz._, Scalaz._ | |
//import cats._, cats.data._, cats.implicits._ | |
//import cats.free._ | |
object ScalazVersion { | |
object free { // our dsl | |
sealed trait TerminalF[A] // an f-algebra which is a sum type | |
type Terminal[A] = Free[TerminalF, A] //free | |
final case class Print(a: Int) extends TerminalF[Unit] | |
final case class Read() extends TerminalF[Int] | |
implicit val terminalFunctor: Functor[TerminalF] = new Functor[TerminalF] { //sadly, can't derive functor | |
def map[A, B](fa: TerminalF[A])(f: A => B): TerminalF[B] = fa.asInstanceOf[TerminalF[B]] | |
} | |
// smart constructors | |
def print(a: Int): Terminal[Unit] = Free.liftF(Print(a)) | |
def read(): Terminal[Int] = Free.liftF(Read()) | |
} | |
object cofree { //our interpreter | |
trait CoTerminalF[A] { //product type. A is a continuation | |
def coPrint(i: Int): A | |
def coRead: (Int, A) | |
} | |
implicit object coterminalFunctor extends Functor[CoTerminalF] { | |
def map[A, B](fa: CoTerminalF[A])(f: A => B): CoTerminalF[B] = new CoTerminalF[B] { | |
def coPrint(i: Int): B = f(fa.coPrint(i)) | |
def coRead: (Int, B) = { | |
val k = fa.coRead | |
(k._1, f(k._2)) | |
} | |
} | |
} | |
type CoTerminal[A] = Cofree[CoTerminalF, A] //cofree | |
} | |
implicit object coterminal_zap_terminal extends Zap[cofree.CoTerminalF, free.TerminalF] { | |
override def zapWith[A, B, C](fa: cofree.CoTerminalF[A], gb: free.TerminalF[B])(f: (A, B) => C): C = { | |
gb match { | |
case free.Print(a) => f(fa.coPrint(a), ()) | |
case free.Read() => f.tupled(fa.coRead.swap) | |
} | |
} | |
} | |
} | |
object test extends App { | |
import ScalazVersion.free._ | |
import ScalazVersion.cofree._ | |
def interp: CoTerminal[Unit] = | |
Cofree.unfoldC[CoTerminalF, Unit](()) { _ => | |
new CoTerminalF[Unit] { | |
def coPrint(i: Int): Unit = (println(s"coprint $i")) | |
def coRead: (Int, Unit) = { (10, println("coread")) } | |
} | |
} | |
val program: Terminal[Int] = for { | |
_ <- print(10) | |
a <- read() | |
b <- read() | |
_ <- print(a + b) | |
} yield b | |
interp.zapWith(program) { (a, b) => println("done") } | |
} |
Besides,
TerminalF:
final case class Print[A](a: Int, k: A) extends TerminalF[A]
looks like adjunct to
def coPrint(i: Int): A
in a sense of that Print which is type of (Int, ?) and CoPrint which is (Int => ?) form an adjunction.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
use non-GADT encoding. it works.