Advertisement
Guest User

Untitled

a guest
Mar 30th, 2017
55
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.07 KB | None | 0 0
  1. // The expression problem is a new name for an old problem. The goal is to
  2. // define a datatype by cases, where one can add new cases to the datatype and
  3. // new functions over the datatype, without recompiling existing code, and while
  4. // retaining static type safety (e.g., no casts).
  5. // (Philip Wadler)
  6.  
  7. import scala.language.implicitConversions
  8.  
  9. object ExpressionProblem extends App {
  10.  
  11. // class Eval a where
  12. // eval :: a -> Int
  13. trait Eval[A] {
  14. def eval(expr: A): Int
  15. }
  16.  
  17. //////////////////////////////////////////
  18. // HERE'S THE MAGIC
  19. //
  20. // data Expr = forall t. Eval t => Expr t
  21. trait Expr {
  22. type T
  23. val t: T
  24. val evalInst: Eval[T]
  25. }
  26.  
  27. object Expr {
  28. def apply[T0 : Eval](t0: T0) = new Expr {
  29. type T = T0
  30. val t = t0
  31. val evalInst = implicitly[Eval[T]]
  32. }
  33. }
  34.  
  35. // Default boxing is needed
  36. implicit def box[T : Eval](t: T) = Expr(t)
  37.  
  38. // instance Eval Expr where
  39. // eval (Expr e) = eval e
  40. implicit object exprInstance extends Eval[Expr] {
  41. def eval(e: Expr) = e.evalInst.eval(e.t)
  42. }
  43.  
  44. // NOTE: Haskell's name lookup makes this unnecessary; however, in order to
  45. // avoid explicitly specifying `exprInstance.eval` each time when we call it
  46. // recursively, simply define an alias.
  47. def evaluate = exprInstance.eval _
  48.  
  49. // data BaseExpr = Const Int | Add Expr Expr | Mul Expr Exp
  50. sealed abstract class BaseExpr
  51. case class Const(c: Int) extends BaseExpr
  52. case class Add(lhs: Expr, rhs: Expr) extends BaseExpr
  53. case class Mul(lhs: Expr, rhs: Expr) extends BaseExpr
  54.  
  55. // instance Eval BaseExpr where
  56. // eval (Const n) = n
  57. // eval (Add a b) = eval a + eval b
  58. // eval (Mul a b) = eval a * eval b
  59. implicit object baseExprInstance extends Eval[BaseExpr] {
  60. def eval(baseExpr: BaseExpr): Int =
  61. baseExpr match {
  62. case Const(c) => c
  63. case Add(lhs, rhs) => evaluate(lhs) + evaluate(rhs)
  64. case Mul(lhs, rhs) => evaluate(lhs) + evaluate(rhs)
  65. }
  66. }
  67.  
  68. // Implicit conversions for all base expressions
  69. //
  70. // NOTE: This is only needed because we created a new hierarchy instead of
  71. // enrolling each type to `Eval` on its own. Otherwise, the boxing function
  72. // would suffice.
  73. implicit def baseExprToExpr[T <: BaseExpr](t: T): Expr = Expr[BaseExpr](t)
  74.  
  75. ///////////////////////////////////////////////
  76. // Possibly somewhere else (other module/lib).
  77. ///////////////////////////////////////////////
  78.  
  79. // data SubExpr = Sub Expr Exp
  80. case class SubExpr(val lhs: Expr, val rhs: Expr)
  81.  
  82. // instance Eval SubExpr where
  83. // eval (Sub a b) = eval a - eval b
  84. implicit object subExprInstance extends Eval[SubExpr] {
  85. def eval(subExpr: SubExpr): Int =
  86. evaluate(subExpr.lhs) - evaluate(subExpr.rhs)
  87. }
  88.  
  89. // NOTE: We don't have to provide an implicit conversion to Expr as the
  90. // default `box` one suffices.
  91.  
  92. object Test {
  93. val exprs: List[Expr] = List(
  94. SubExpr(Const(10), Const(3)),
  95. Add(Const(1), Const(1))
  96. )
  97. }
  98.  
  99. // Just sanity checking, they are not pretty Show-able.
  100. println(Test.exprs)
  101.  
  102. } // ExpressionProblem
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement