Skip to content

Instantly share code, notes, and snippets.

@MasseGuillaume
Last active August 29, 2015 14:14
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 MasseGuillaume/f44db6a0fd94bd32f570 to your computer and use it in GitHub Desktop.
Save MasseGuillaume/f44db6a0fd94bd32f570 to your computer and use it in GitHub Desktop.
ttfi abstracted over Numeric
trait Repr[T]
trait ExpSym[Num, repr[_]] {
def lit: Num => repr[Num]
def neg: repr[Num] => repr[Num]
def add: repr[Num] => repr[Num] => repr[Num]
}
trait MulSym[Num, repr[_]] {
def mul: repr[Num] => repr[Num] => repr[Num]
}
case class NumRepr[T](value: Int) extends Repr[Int]
implicit object ExpSymEvalInt extends ExpSym[Int, NumRepr] {
def lit = x => NumRepr(x)
def neg = x => NumRepr(-x.value)
def add = x => y => NumRepr(x.value + y.value)
}
implicit object MulSymEvalInt extends MulSym[Int, NumRepr] {
def mul = x => y => NumRepr(x.value * y.value)
}
def tf1[repr[_]](implicit s1: ExpSym[Int, repr]): repr[Int] =
s1.lit(1)
identity(tf1[NumRepr])
@suhailshergill
Copy link

@MasseGuillaume the main issue is that we're contradicting ourselves. on the one hand we want tf1 to be generic, but then on the other we hardcode a concrete, specialized witness (i.e. 1). the fix is to parameterize tf1. the below works. also, the way you're using NumRepr, that really should be the Eval case class.

    // let's make the representation domain explicit
    trait Repr[T]

    // container to hold the result of 'Eval'-ing an expression
    case class Eval[T](value: T) extends Repr[T]
    // run the 'Eval' interpreter
    def eval[T]: Eval[T] => T = _.value

    // container to hold the result of 'pretty-printing' an expression
    case class Debug[T](debug: String) extends Repr[T]
    // run the pretty-printing interpreter
    def view[T]: Debug[T] => String = _.debug

    object NumSym {
      trait ExpNumSym[num, repr[_]] {
        def lit: num => repr[num]
        def neg: repr[num] => repr[num]
        def add: repr[num] => repr[num] => repr[num]
      }
      // cleaner 'constructors'
      def Lit[num, repr[_]](x: num)(implicit s1: ExpNumSym[num, repr]): repr[num] = {
        s1.lit(x)
      }
      def Neg[num, repr[_]](e: repr[num])(implicit s1: ExpNumSym[num, repr]): repr[num] = {
        s1.neg(e)
      }
      def Add[num, repr[_]](e1: repr[num])(e2: repr[num])(implicit s1: ExpNumSym[num, repr]): repr[num] = {
        s1.add(e1)(e2)
      }

      trait MulNumSym[num, repr[_]] {
        def mul: repr[num] => repr[num] => repr[num]
      }
      def Mul[num, repr[_]](e1: repr[num])(e2: repr[num])(implicit s1: MulNumSym[num, repr]): repr[num] = {
        s1.mul(e1)(e2)
      }

      implicit object ExpSymIntEval extends ExpNumSym[Int, Eval] {
        def lit = Eval(_)
        def neg = x => Eval(-x.value)
        def add = x => y => Eval(x.value + y.value)
      }

      implicit object MulSymIntEval extends MulNumSym[Int, Eval] {
        def mul = x => y => Eval(x.value * y.value)
      }

      def tf1[num, repr[_]](x: num)(implicit s1: ExpNumSym[num, repr]): repr[num] =
        Add(Neg(Lit[num, repr](x)))(Lit[num, repr](x))

      val result1 = eval(tf1(10))
    }

the code above can also be seen in this commit

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment