Филарета обнови решението на 14.11.2012 12:11 (преди почти 13 години)
+class Expr
+  def self.build(expression)
+    operation,a,b = expression
+      case operation
+      when :+ then Addition.build a,b
+      when :* then Multiplication.build a,b
+      when :- then Negation.build a
+      when :sin then Sine.build a
+      when :cos then Cosine.build a
+      when :variable then Variable.new a
+      when :number then Number.new a
+      end
+  end
+
+  def *(other)
+    Multiplication.new self, other
+  end
+
+  def +(other)
+    Addition.new self, other
+  end
+
+  def -@
+    Negation.new self
+  end
+end
+
+class Negation < Expr
+  attr_accessor :operand
+
+  def initialize(operand)
+    @operand = operand
+  end
+
+  def self.build(operand)
+    a = Expr.build operand
+    new a
+  end
+
+  def evaluate(environment)
+    negative =  @operand.evaluate environment
+    - negative
+  end
+
+  def exact?
+    @operand.exact?
+  end
+
+  def simplify
+    if exact?
+      @operand.simplify
+    else
+      Number.new - operand
+    end
+  end
+
+  def derive(variable)
+    result = operand.derive variable
+    - result.simplify
+  end
+
+  def ==(other)
+    if other.instance_of? Negation
+      @operand == other.operand
+    else
+      false
+    end
+  end
+end
+
+class Variable < Expr
+  attr_accessor :variable
+
+  def initialize(variable)
+    @variable = variable
+  end
+
+  def derive(variable)
+    if @variable == variable
+      Number.new 1
+    else
+      Number.new 0
+    end
+  end
+
+  def evaluate(environment)
+    environment.each{ |key,value| if @variable == key then @variable = value end }
+    @variable
+  end
+
+  def simplify
+    Variable.new variable
+  end
+
+  def exact?
+    true
+  end
+
+  def ==(other)
+    if other.instance_of? Variable
+     @variable == other.variable
+   else
+     false
+    end
+  end
+end
+
+class Number < Expr
+  attr_accessor :number
+
+  def initialize(number)
+    @number = number
+  end
+
+  def derive(variable)
+    Number.new 0
+  end
+
+  def simplify
+    Number.new @number
+  end
+
+  def exact?
+    false
+  end
+
+  def evaluate(environment)
+    @number
+  end
+
+  def ==(other)
+    if other.instance_of? Number
+     @number == other.number
+    else
+     false
+   end
+  end
+end
+
+class Sine < Expr
+  attr_accessor :argument
+
+  def initialize(argument)
+    @argument = argument
+  end
+
+  def self.build(operand)
+    a = Expr.build operand
+    new a
+  end
+
+  def evaluate(environment)
+    Math.sin(@argument.evaluate environment)
+  end
+
+  def derive(variable)
+    first =  Cosine.new argument.derive variable
+    second = (Variable.new variable).derive variable
+    result = first * second
+    result.simplify
+  end
+
+  def simplify
+    if @argument.exact? then @argument.simplify
+     elsif @argument.number == 0 then Number.new 0
+     elsif @argument.number == 90 then Number.new 1
+    end
+  end
+
+  def exact?
+    @argument.exact?
+  end
+
+  def ==(other)
+    if other.instance_of? Sine
+     @argument == other.argument
+   else
+    false
+   end
+  end
+end
+
+class Cosine < Expr
+  attr_accessor :argument
+
+  def initialize(argument)
+    @argument = argument
+  end
+
+  def self.build(operand)
+    a = Expr.build operand
+    new a
+  end
+
+  def evaluate(environment)
+    Math.cos(@argument.evaluate environment)
+  end
+
+  def derive(variable)
+    first =  Sine.new argument.derive variable
+    second = (Variable.new variable).derive variable
+    result = first * - second
+    result.simplify
+  end
+
+  def simplify
+    if @argument.exact? then @argument.simplify
+    elsif @argument.number == 0 then Number.new 1
+    elsif @argument.number == 90 then Number.new 0
+    end
+  end
+
+  def exact?
+    @argument.exact?
+  end
+
+  def ==(other)
+    if other.instance_of? Cosine
+     @argument == other.argument
+   else
+    false
+  end
+  end
+end
+
+class Addition < Expr
+  attr_accessor :addend_1, :addend_2
+
+  def initialize(operand_1,operand_2)
+    @addend_1 = operand_1
+    @addend_2 = operand_2
+  end
+
+  def self.build(operand_1,operand_2)
+    a = Expr.build operand_1
+    b = Expr.build operand_2
+    new a,b
+  end
+
+  def derive(variable)
+    first =  addend_1.derive variable
+    second = addend_2.derive variable
+    result = first + second
+    result.simplify
+  end
+
+  def simplify
+    if @addend_1.instance_of? Number and @addend_2.instance_of? Number then
+     Number.new @addend_1.number + @addend_2.number
+    elsif @addend_1.instance_of? Number and @addend_1.number == 0 then @addend_2.simplify
+    elsif @addend_2.instance_of? Number and @addend_2.number == 0 then @addend_1.simplify
+    elsif @addend_1.exact? then @addend_1.simplify + @addend_2
+    elsif @addend_2.exact? then @addend_1 + @addend_2.simplify
+    elsif @addend_1.exact? then @addend_1.simplify + @addend_2.simplify
+    end
+  end
+
+  def exact?
+    @addend_1.exact? or @addend_2.exact?
+  end
+
+  def evaluate(environment)
+    first = @addend_1.evaluate environment
+    second = @addend_2.evaluate environment
+    first + second
+  end
+
+  def ==(other)
+    if other.instance_of? Addition
+     @addend_1 == other.addend_1 and @addend_2 == other.addend_2
+   else
+    false
+   end
+  end
+end
+
+class Multiplication < Expr
+  attr_accessor :multiplicand, :multiplier
+
+  def initialize(operand_1,operand_2)
+    @multiplicand = operand_1
+    @multiplier = operand_2
+  end
+
+  def self.build(operand_1,operand_2)
+    a = Expr.build operand_1
+    b = Expr.build operand_2
+    new a,b
+  end
+
+  def derive(variable)
+    first = multiplicand.derive variable
+    second = multiplier.derive variable
+    derived_1 = Multiplication.new first, multiplier
+    derived_2 = Multiplication.new multiplicand, second
+    result = derived_1 + derived_2
+    result.simplify
+  end
+
+  def simplify
+    unless @multiplicand.exact?
+      if @multiplicand.number == 0 then @multiplicand.simplify
+      elsif @multiplicand.number == 1 then @multiplier.simplify
+      elsif @multiplicand.instance_of? Number then @multiplier.simplify
+      end
+    else
+      if @multiplier.exact? then @multiplicand.simplify * @multilier.simplify
+      elsif @multiplier.number == 0 then @multiplier.simplify
+      elsif @multiplier.number == 1 then @multiplicand.simplify
+      elsif @multiplier.instance_of? Number then @multiplicand.simplify
+      end
+    end
+  end
+
+  def exact?
+    @multiplicand.exact? or @multiplier.exact?
+  end
+
+  def evaluate(environment)
+    first = @multiplicand.evaluate environment
+    second = @multiplier.evaluate environment
+    first * second
+  end
+
+  def ==(other)
+    if other.instance_of? Multiplication
+     @multiplicand == other.multiplicand and @multiplier == other.multiplier
+    else
+     false
+    end
+  end
+end
