xacid: (Default)
xacid ([personal profile] xacid) wrote2016-12-09 05:56 pm
Entry tags:

More tagless

object Tagless extends App {

  trait Sym[F[_]] {
    def lit[A]: (String, A) => F[A]
    def app[A, B]: F[A => B] => F[A] => F[B]
    def lam[A, B]: String => (F[A] => F[B]) => F[A => B]
  }

  object Sym {
    def apply[F[_] : Sym] = implicitly[Sym[F]]
    def lit[F[_] : Sym, A](s: String, a: A) = 
       Sym[F].lit(s, a)
    def lit[F[_] : Sym, A](a: A) = 
       Sym[F].lit(a.toString, a)
    def app[F[_] : Sym, A, B](f: F[A => B])
       (a: F[A]) = Sym[F].app(f)(a)
    def lam[F[_] : Sym, A, B](s: String)
       (f: (F[A] => F[B])) = Sym[F].lam(s)(f)
  }

  type RunSym[A] = A
  object RunSym extends Sym[RunSym] {
    override def lit[A]: (String, A) => RunSym[A] =
      (_, a) => a
    override def app[A, B]: (RunSym[(A) => B]) => 
      (RunSym[A]) => RunSym[B] = f => a => f(a)
    override def lam[A, B]: String => 
      ((RunSym[A]) => RunSym[B]) => RunSym[(A) => B] =
       s => f => f
  }

  type ShowSym[A] = String
  object ShowSym extends Sym[ShowSym] {
    override def lit[A]: (String, A) => ShowSym[A] = 
      (s, _) => s
    override def app[A, B]: (ShowSym[(A) => B]) => 
      (ShowSym[A]) => ShowSym[B] = f => a => s"$f($a)"
    override def lam[A, B]: String => 
      ((ShowSym[A]) => ShowSym[B]) => ShowSym[(A) => B] =
       s => f => s"($s => ${f(s)})"
  }

  import Sym._

  def PLUS[F[_] : Sym] = lit("+",
    (x: Int) => (y: Int) => x + y)

  def main[F[_] : Sym] = lam("x")((x: F[Int]) =>
    app(app(PLUS)(x))(x))

  def answer[F[_] : Sym] = app(main)(lit(21))

  println(s"${answer(ShowSym)} = ${answer(RunSym)}")

}

// (x => +(x)(x))(21) = 42