Илиян обнови решението на 14.11.2012 16:31 (преди почти 13 години)
+class Expr
+  def self.build(sexpression)
+    case sexpression[0]
+      when :number       then Number.new(sexpression[1])
+      when :variable     then Variable.new(sexpression[1])
+      when :+            then Addition.new(build(sexpression[1]), build(sexpression[2]))
+      when :*            then Multiplication.new(build(sexpression[1]), build(sexpression[2]))
+      when :-            then Negation.new(build(sexpression[1]))
+      when :sin          then Sine.new(build(sexpression[1]))
+      when :cos          then Cosine.new(build(sexpression[1]))
+    end
+  end
+
+  def ==(other)
+    instance_of? other.class
+  end
+
+  def evaluate(environment = {})
+  end
+
+  def simplify
+  end
+
+  def derive(variable)
+  end
+
+  def exact?
+    false
+  end
+end
+
+class Unary < Expr
+  attr_accessor :operand
+
+  def initialize(operand)
+    @operand = operand
+  end
+
+  def ==(other)
+    super and operand.instance_of? other.operand.class and operand == other.operand
+  end
+
+  def exact?
+    operand.exact?
+  end
+end
+
+class Binary < Expr
+  attr_accessor :left_operand, :right_operand
+
+  def initialize(left_operand, right_operand)
+    @left_operand = left_operand
+    @right_operand = right_operand
+  end
+
+  def ==(other)
+    super and
+      left_operand.instance_of? other.left_operand.class and
+      right_operand.instance_of? other.right_operand.class and
+      left_operand == other.left_operand and
+      right_operand == other.right_operand
+  end
+
+  def exact?
+    left_operand.exact? and right_operand.exact?
+  end
+end
+
+class Number < Unary
+  def evaluate(environment = {})
+    operand
+  end
+
+  def simplify
+    Number.new(operand)
+  end
+
+  def derive(variable)
+    Number.new(0)
+  end
+
+  def exact?
+    true
+  end
+end
+
+class Addition < Binary
+  def evaluate(environment = {})
+    left_operand.evaluate(environment) + right_operand.evaluate(environment)
+  end
+
+  def simplify
+    new_left_operand, new_right_operand = left_operand.simplify, right_operand.simplify
+
+    if new_left_operand == Number.new(0)
+      new_right_operand
+    elsif new_right_operand == Number.new(0)
+      new_left_operand
+    elsif new_left_operand.exact? and new_right_operand.exact?
+      Number.new(Addition.new(new_left_operand, new_right_operand).evaluate)
+    else
+      Addition.new(new_left_operand, new_right_operand)
+    end
+  end
+
+  def derive(variable)
+    Addition.new(left_operand.derive(variable), right_operand.derive(variable)).simplify
+  end
+end
+
+class Multiplication < Binary
+  def evaluate(environment = {})
+    left_operand.evaluate(environment) * right_operand.evaluate(environment)
+  end
+
+  def simplify
+    new_left_operand, new_right_operand = left_operand.simplify, right_operand.simplify
+
+    if new_left_operand == Number.new(0) or new_right_operand == Number.new(0)
+      Number.new(0)
+    elsif new_left_operand == Number.new(1)
+      new_right_operand
+    elsif new_right_operand == Number.new(1)
+      new_left_operand
+    elsif new_left_operand.exact? and new_right_operand.exact?
+      Number.new(Multiplication.new(new_left_operand, new_right_operand).evaluate)
+    else
+      Multiplication.new(new_left_operand, new_right_operand)
+    end
+  end
+
+  def derive(variable)
+    Addition.new(
+      Multiplication.new(left_operand.derive(variable), right_operand),
+      Multiplication.new(left_operand, right_operand.derive(variable))
+    ).simplify
+  end
+end
+
+class Variable < Unary
+  def evaluate(environment = {})
+    environment[operand] or raise('Variable not found')
+  end
+
+  def simplify
+    Variable.new(operand)
+  end
+
+  def derive(variable)
+    Number.new(variable == operand ? 1 : 0)
+  end
+
+  def exact?
+    false
+  end
+end
+
+class Negation < Unary
+  def evaluate(environment = {})
+    - operand.evaluate(environment)
+  end
+
+  def simplify
+    new_operand = operand.simplify
+    new_operand.exact? ? Number.new(-new_operand.evaluate) : Negation.new(new_operand)
+  end
+
+  def derive(variable)
+    Negation.new(operand.derive(variable)).simplify
+  end
+end
+
+class Sine < Unary
+  def evaluate(environment = {})
+    Math.sin(operand.evaluate(environment))
+  end
+
+  def simplify
+    new_operand = operand.simplify
+    new_operand.exact? ? Number.new(new_operand.evaluate) : Sine.new(new_operand)
+  end
+
+  def derive(variable)
+    Multiplication.new(operand.derive(variable), Cosine.new(operand)).simplify
+  end
+end
+
+class Cosine < Unary
+  def evaluate(environment = {})
+    Math.cos(operand.evaluate(environment))
+  end
+
+  def simplify
+    new_operand = operand.simplify
+    new_operand.exact? ? Number.new(new_operand.evaluate) : Cosine.new(new_operand)
+  end
+
+  def derive(variable)
+    Multiplication.new(operand.derive(variable), Negation.new(Sine.new(operand))).simplify
+  end
+end
