title: Advanced pattern matching in haxe (compared with scala example)
body: <p>Consider the following Scala cases: (inspired by this <a href="http://kerflyn.wordpress.com/2011/02/14/playing-with-scalas-pattern-matching/" rel="nofollow">blog post</a>)</p>
  
  <pre><code>sealed abstract class Expr
  case class X() extends Expr
  case class Const(value : Int) extends Expr
  case class Add(left : Expr, right : Expr) extends Expr
  case class Mult(left : Expr, right : Expr) extends Expr
  case class Neg(expr : Expr) extends Expr
  </code></pre>
  
  <p>In Haxe this would respond to:</p>
  
  <pre><code>enum Expr {
      X();
      Const(val:Int);
      Add(left:Expr, right:Expr);
      Mult(left:Expr, right:Expr);
      Neg(expr:Expr);
  }
  </code></pre>
  
  <p>Writing an eval function for any kind of nested expression is quite straightforward in both languages. However I am interested in the following simplify function (focuses only on multiplication):</p>
  
  <p>In scala:</p>
  
  <pre><code>def simplify(expression: Expr): Expr = expression match {
      case Mult(_, Const(0)) =&gt; Const(0)
      case Mult(Const(0), _) =&gt; Const(0)
      case Mult(left, Const(1)) =&gt; simplify(left)
      case Mult(Const(1), right) =&gt; simplify(right)
      case Mult(Const(leftVal), Const(rightVal)) =&gt; Const(leftVal * rightVal)
      case Mult(left, right) =&gt; Mult(simplify(left),simplify(right))
  
      case Add(left, right) =&gt; Add(simplify(left),simplify(right))
      case Neg(left) =&gt; simplify(left)
      case _ =&gt; expression
  }
  </code></pre>
  
  <p>My question: What is the most concise/clean way to write something equivalent in Haxe?
  These are my attempts but I'm not quite satisfied with either.</p>
  
  <p>First one (kind of bloathed):</p>
  
  <pre><code>public static function simplify(expr:Expr):Expr{
      switch(expr){
          case Mult(left, right):
              if(left.enumEq(Const(0)) || right.enumEq(Const(0))) return Const(0);
              switch(left){
                  case Const(leftVal):
                      if(leftVal == 1) return right.simplify();
                      switch(right){
                          case Const(rightVal): return Const(rightVal * leftVal);
                          default:
                      }
                  default:
                      switch(right){
                          case Const(rightVal):
                              if(rightVal == 1) return left.simplify();
                          default: 
                      }
              }
              return Mult(left.simplify(), right.simplify());
          case Add(left, right): return Add(left.simplify(), right.simplify());
          case Neg(expr): return Neg(expr.simplify());
          default: return expr;
      }
  }
  </code></pre>
  
  <p>Another try (more concise, but hacky):</p>
  
  <pre><code>public static function simplify(expr:Expr):Expr{
      switch(expr){
          case Mult(left, right):
              if(left.enumEq(Const(0)) || right.enumEq(Const(0))) return Const(0);
              if(left.enumEq(Const(1))) return right.simplify();
              if(right.enumEq(Const(1))) return left.simplify();
              if(left.enumConstructor() == right.enumConstructor() &amp;&amp;
                      left.enumConstructor() == Const(null).enumConstructor())
                  return Const(Std.int(left.enumParameters()[0] *
                      right.enumParameters()[0]));
              return Mult(left.simplify(), right.simplify());
          case Add(left, right): return Add(left.simplify(), right.simplify());
          case Neg(expr): return Neg(expr.simplify());
          default: return expr;
      }
  }
  </code></pre>