Skip to content

Instantly share code, notes, and snippets.

@ahoy-jon
Created June 7, 2020 13:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ahoy-jon/3ae79722f273be9a06c66ee5f12ea4b7 to your computer and use it in GitHub Desktop.
Save ahoy-jon/3ae79722f273be9a06c66ee5f12ea4b7 to your computer and use it in GitHub Desktop.
sealed abstract class Cont[Result, +H] {
final def map[H2](fn: H => H2): Cont[Result, H2] = flatMap(h => Cont.pure(fn(h)))
final def flatMap[H2](fn: H => Cont[Result, H2]): Cont[Result, H2] = Cont.FlatMapped(this, fn)
def apply(fn: H => Result): Result
}
object Cont {
case class Wrap[Result, H](f: (H => Result) => Result) extends Cont[Result, H] {
override def apply(fn: H => Result): Result = f(fn)
}
case class FlatMapped[Result, H1, H2](cont: Cont[Result, H1], next: H1 => Cont[Result, H2]) extends Cont[Result, H2] {
override def apply(fn: H2 => Result): Result =
cont.apply(h1 => next(h1).apply(fn))
}
def pure[R, H](h: H): Cont[R, H] = Wrap(f => f(h))
def from[Result, H](fn: (H => Result) => Result): Cont[Result, H] = Wrap(fn)
}
def add[R](x: Int, y: Int): Cont[R, Int] = Cont.pure(x + y)
def add2[R](x: Int, y: Int): Cont[R, Int] = Cont.from(continue => continue(x + y))
def times[R](x: Int, y: Int): Cont[R, Int] = Cont.pure(x * y)
def square[R](x: Int): Cont[R, Int] = times(x, 2)
def pyth[R](x: Int, y: Int): Cont[R, Int] =
for {
x2 <- square(x)
y2 <- square(y)
z2 <- add(x2, y2)
} yield z2
pyth(3, 5)(println)
def debug[R, H](cont:Cont[R, H])(f: (H => R)): R = {
cont match {
case w:Cont.Wrap[R,H] => w(h => {
println(s"debug wrap $h")
val r = f(h)
println(s"debug wrap eval $h => $r")
r
})
case s:Cont.FlatMapped[R,_, H] =>
debug(s.cont)(h1 => {
println(s"debug flatMap hidden $h1")
val r: R = debug(s.next(h1))(f)
r
})
}
}
debug[Unit, Int](pyth[Unit](3,4))(println)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment