Skip to content

Instantly share code, notes, and snippets.

@manuelleduc
Created June 28, 2017 12:20
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 manuelleduc/6dc31cd246c2f95a54ef84822dc2df84 to your computer and use it in GitHub Desktop.
Save manuelleduc/6dc31cd246c2f95a54ef84822dc2df84 to your computer and use it in GitHub Desktop.
Modular visitor in scala
package modularexp
import scala.language.higherKinds
/**
* Created by mleduc on 28/06/17.
*/
trait Exp[A]
trait Sum[A] extends Exp[A] {
val lhs: Exp[A] with A
val rhs: Exp[A] with A
}
trait Const[A] extends Exp[A] {
val value: Int
}
trait VisitorSum[A] {
def visitSum(e: Sum[Acceptor[A]]): A
}
trait VisitorConst[A] {
def visitConst(e: Const[Acceptor[A]]): A
}
trait Acceptor[A] {
def accept(): A
}
class PrettyPrintVisitor extends VisitorConst[String] with VisitorSum[String] {
override def visitConst(e: Const[Acceptor[String]]): String = e.value.toString
override def visitSum(e: Sum[Acceptor[String]]): String = s"(${e.lhs.accept()} + ${e.rhs.accept()})"
}
trait CalculateVisitorConst extends VisitorConst[Int] {
override def visitConst(e: Const[Acceptor[Int]]): Int = e.value
}
trait CalculateVisitorSum extends VisitorSum[Int] {
override def visitSum(e: Sum[Acceptor[Int]]): Int = e.lhs.accept() + e.rhs.accept()
}
object Test extends App {
val ppv = new PrettyPrintVisitor
def program[A](ppv: VisitorSum[A] with VisitorConst[A]): Sum[Acceptor[A]] with Acceptor[A] = {
val buildSum = initBuildSum(ppv)
val buildConst = initBuildConst(ppv)
val lhs = buildConst(1)
val rhs = buildConst(2)
val program = buildSum(lhs, rhs)
program
}
def initBuildSum[A](ppv: VisitorSum[A]): (Exp[Acceptor[A]] with Acceptor[A], Exp[Acceptor[A]] with Acceptor[A]) => Sum[Acceptor[A]] with Acceptor[A] = (lhs_, rhs_) => {
new Sum[Acceptor[A]] with Acceptor[A] {
override val lhs: Exp[Acceptor[A]] with Acceptor[A] = lhs_
override val rhs: Exp[Acceptor[A]] with Acceptor[A] = rhs_
override def accept() = ppv.visitSum(new Sum[Acceptor[A]] {
override val lhs: Exp[Acceptor[A]] with Acceptor[A] = lhs_
override val rhs: Exp[Acceptor[A]] with Acceptor[A] = rhs_
})
}
}
def initBuildConst[A](ppv: VisitorConst[A]): (Int) => Const[Acceptor[A]] with Acceptor[A] = (nbr) => {
new Const[Acceptor[A]] with Acceptor[A] {
override val value: Int = nbr
override def accept(): A = ppv.visitConst(new Const[Acceptor[A]] {
override val value: Int = nbr
})
}
}
println(program(ppv).accept())
println(program(new CalculateVisitorConst with CalculateVisitorSum {}).accept())
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment