Мартин обнови решението на 10.11.2012 19:26 (преди почти 13 години)
+class Expr
+
+  def self.build(tree)
+    if tree.count == 2 then Unary.build(tree.fetch(0), tree.fetch(1))
+    else Binary.build(tree.fetch(0), tree.fetch(1), tree.fetch(2))
+    end
+  end
+
+end
+
+class Unary < Expr
+
+  include Math
+
+  def self.build(operation, operand)
+    case operation
+      when :sine then Sine.new(Expr.build operand)
+      when :cosine then Cosine.new(Expr.build operand)
+      when :number then Number.new(operand)
+      when :variable then Variable.new(operand)
+      when :- then Negation.new(Expr.build operand)
+    end
+  end
+
+  def ==(other)
+    if self.class != other.class then false
+    elsif self.operand != other.operand then false
+    else true
+    end
+  end
+
+  def !=(other)
+    not self == other
+  end
+
+  def exact?
+    operand.exact?
+  end
+
+end
+
+class Number < Unary
+
+  attr_accessor :operand
+
+  def initialize(operand)
+    @operand = operand
+  end
+
+  def evaluate(environment = {})
+    operand
+  end
+
+  def simplify
+    self
+  end
+
+  def exact?
+    true
+  end
+
+  def derive(variable)
+    Number.new(0)
+  end
+
+end
+
+class Variable < Unary
+
+  attr_accessor :operand
+
+  def initialize(operand)
+    @operand = operand
+  end
+
+  def exact?
+    false
+  end
+
+  def evaluate(environment = {})
+    if environment.has_key?(operand) then return environment[operand]
+    end
+    puts("you have to define #{operand}")
+    exit
+  end
+
+  def simplify
+    self
+  end
+
+  def derive(variable)
+    if variable == operand then Number.new(1)
+    else Number.new(0)
+    end
+  end
+
+end
+
+class Negation < Unary
+
+  attr_accessor :operand
+
+  def initialize(operand)
+    @operand = operand
+  end
+
+  def evaluate(environment = {})
+    (-1) * operand.evaluate(environment)
+  end
+
+  def derive(variable)
+    Negation.new(operand.derive(variable)).simplify
+  end
+
+  def simplify
+    if operand == Number.new(0)
+      Number.new(0)
+    else
+      Negation.new(operand.simplify)
+    end
+  end
+
+end
+
+class Sine < Unary
+
+  attr_accessor :operand
+
+  def initialize(operand)
+    @operand = operand
+  end
+
+  def evaluate(environment = {})
+    sin(operand.evaluate(environment))
+  end
+
+  def derive(variable)
+    Multiplication.new(operand.derive(variable), Cosine.new(operand)).simplify
+  end
+
+  def simplify
+    operand.simplify
+  end
+
+end
+
+class Cosine < Unary
+
+  attr_accessor :operand
+
+  def initialize(operand)
+    @operand = operand
+  end
+
+  def evaluate(environment = {})
+    cos(operand.evaluate(environment))
+  end
+
+  def derive(variable)
+    Multiplication.new(operand.derive(variable), Negation.new(Sine.new(operand))).simplify
+  end
+
+  def simplify
+    operand.simplify
+  end
+
+end
+
+class Binary < Expr
+
+  def self.build(operation, left_operand, right_operand)
+    case operation
+      when :+ then Addition.new(Expr.build(left_operand), Expr.build(right_operand))
+      when :* then Multiplication.new(Expr.build(left_operand), Expr.build(right_operand))
+    end
+  end
+
+  def exact?
+    left_operand.exact? and right_operand.exact?
+  end
+
+  def ==(other)
+    if self.class != other.class then false
+    elsif self.left_operand != other.left_operand then false
+    elsif self.right_operand != other.right_operand then false
+    else true
+    end
+  end
+
+  def !=(other)
+    not self == other
+  end
+
+end
+
+class Addition < Binary
+
+  attr_accessor :left_operand, :right_operand
+
+  def initialize(left_operand,right_operand)
+    @left_operand = left_operand
+    @right_operand = right_operand
+  end
+
+  def evaluate(environment = {})
+    left_operand.evaluate(environment) + right_operand.evaluate(environment)
+  end
+
+  def derive(variable)
+    Addition.new(left_operand.derive(variable), right_operand.derive(variable)).simplify
+  end
+
+  def simplify
+    if exact?
+      return Number.new(evaluate)
+    end
+    if left_operand == Number.new(0) then right_operand.simplify
+    elsif right_operand == Number.new(0) then left_operand.simplify
+    else Addition.new(left_operand.simplify, right_operand.simplify)
+    end
+  end
+
+end
+
+class Multiplication < Binary
+
+  attr_accessor :left_operand, :right_operand
+
+  def initialize(left_operand,right_operand)
+    @left_operand = left_operand
+    @right_operand = right_operand
+  end
+
+  def evaluate(environment = {})
+    left_operand.evaluate(environment) * right_operand.evaluate(environment)
+  end
+
+  def derive(variable)
+    left_aggend = Multiplication.new(left_operand.derive(variable), right_operand)
+    right_aggend = Multiplication.new(left_operand, right_operand.derive(variable))
+    Addition.new(left_aggend, right_aggend)
+  end
+
+  def simplify
+    if exact?
+      return Number.new(evaluate)
+    end
+    if left_operand == Number.new(0) then Number.new(0)
+      elsif right_operand == Number.new(0) then Number.new(0)
+      elsif left_operand == Number.new(1) then right_operand.simplify
+      else Multiplication.new(left_operand.simplify, right_operand.simplify)
+    end
+  end
+
+end
