/*  CSci 658, Software Language Engineering 
    Expression Tree Code, Original Version, adapted from Section 6 
      of "A Scala Tutorials for Java Programmers"
    Adapted by H. Conrad Cunningham

1234567890123456789012345678901234567890123456789012345678901234567890

2008-09-10: (V1) Typed from tutorial "A Scala Tutorials for Java 
            Programmers" by student Prachi Mann and adapted by 
            Cunningham for a programming assignment.
2012-03-06: (V1a) Corrected "int" to "Int".
2018-02-03: (V1b) Updated comments and formatting.

This program is a predecessor to programs ExprCase.scala and
ExprObj.scala.

This file was recreated from Section 6 of "A Scala Tutorials for Java
Programmers" for a programming assignment in the initial Scala-based
offering of Multiparadigm Programming (later numbered CSci 556) in
Fall 2008.

*/

/* Expression Trees */
abstract class Tree
case class Sum(l: Tree, r: Tree) extends Tree
case class Var(n: String) extends Tree
case class Const(v: int) extends Tree

/* Expression Tree operations and testing */
object Expressions {

  type Environment = String => Int

  def eval(t: Tree, env: Environment): int = t match {
    case Sum(l,r) => eval(l,env) + eval(r,env)
    case Var(n)   => env(n)
    case Const(v) => v
  }

  def derive(t: Tree, v: String): Tree = t match {
    case Sum(l,r)           => Sum(derive(l,v), derive(r,v))
    case Var(n) if (v == n) => Const(1)
    case _                  => Const(0)
  }

  def main(args: Array[String]) {
    val exp: Tree = Sum(Sum(Var("x"),Var("x")),Sum(Const(7),Var("y")))
    val env: Environment = { case "x" => 5 case "y" => 7 }
    println("Expression: " + exp)
    println("Evaluation with x=5, y=7: " + eval(exp,env))
    println("Derivative relative to x:\n  " + derive(exp, "x"))
    println("Derivative relative to y:\n  " + derive(exp, "y"))
  }
}
