Красимир обнови решението на 09.11.2012 21:37 (преди почти 13 години)
+class Expr
+  @@types = {}
+
+  def ==(other)
+    other.class == self.class and other.state == state
+  end
+
+  def self.build(s_expr)
+    type, *s_args = *s_expr
+    @@types[type].build(s_args)
+  end
+
+  def +(other)
+    Addition.new(self, other)
+  end
+
+  def *(other)
+    Multiplication.new(self, other)
+  end
+
+  def -@
+    Negation.new(self)
+  end
+
+  def simplify
+    self
+  end
+end
+
+class Atomic < Expr
+  attr_accessor :value
+
+  def initialize(value)
+    @value = value
+  end
+
+  def self.build(value)
+    new value.first
+  end
+
+  alias state value
+end
+
+class Number < Atomic
+  @@types[:number] = self
+
+  Zero = self.new(0)
+  One = self.new(1)
+
+  def evaluate(environment = {})
+    value
+  end
+
+  def derive(variable)
+    Zero
+  end
+
+  def exact?
+    true
+  end
+end
+
+class Variable < Atomic
+  @@types[:variable] = self
+
+  def evaluate(environment = {})
+    if environment.has_key? value
+      environment[value]
+    else
+      raise 'Uninitialized variable during evaluation.'
+    end
+  end
+
+  def derive(variable)
+    if value == variable
+      Number::One
+    else
+      Number::Zero
+    end
+  end
+
+  def exact?
+    false
+  end
+end
+
+class Composite < Expr
+  attr_accessor :args
+
+  def initialize(*args)
+    @args = args
+  end
+
+  def self.build(s_args)
+    new(*s_args.map { |s_expr| Expr.build(s_expr) })
+  end
+
+  alias state args
+
+  def evaluate(environment = {})
+    self.class.compute_value(*args.map { |expr| expr.evaluate(environment) })
+  end
+
+  def derive(variable)
+    arg_derives = args.map { |expr| expr.derive(variable) }
+    self.class.compute_derivative(*args, *arg_derives).simplify
+  end
+
+  def exact?
+    args.all? { |expr| expr.exact? }
+  end
+
+  def self.simplify_step(whole, *_)
+    whole
+  end
+
+  def simplify
+    if exact?
+      Number.new(evaluate)
+    else
+      simple_args = args.map { |expr| expr.simplify }
+      whole = self.class.new(*simple_args)
+      self.class.simplify_step(whole, *simple_args)
+    end
+  end
+end
+
+class Addition < Composite
+  @@types[:+] = self
+
+  def self.compute_value(a, b)
+    a + b
+  end
+
+  def self.compute_derivative(f, g, df, dg)
+    df + dg
+  end
+
+  def self.simplify_step(whole, a, b)
+    if a == Number::Zero
+      b
+    elsif b == Number::Zero
+      a
+    else
+      whole
+    end
+  end
+end
+
+class Multiplication < Composite
+  @@types[:*] = self
+
+  def self.compute_value(a, b)
+    a * b
+  end
+
+  def self.compute_derivative(f, g, df, dg)
+    df * g + f * dg
+  end
+
+  def self.simplify_step(whole, a, b)
+    if a == Number::Zero or b == Number::Zero
+      Number::Zero
+    elsif a == Number::One
+      b
+    elsif b == Number::One
+      a
+    else
+      whole
+    end
+  end
+end
+
+class Negation < Composite
+  @@types[:-] = self
+
+  def self.compute_value(a)
+    -a
+  end
+
+  def self.compute_derivative(f, df)
+    -df
+  end
+
+  def self.simplify_step(whole, a)
+    if Negation == a.class
+      a.args.first
+    else
+      whole
+    end
+  end
+end
+
+class Sine < Composite
+  @@types[:sin] = self
+
+  def self.compute_value(a)
+    Math.sin(a)
+  end
+
+  def self.compute_derivative(f, df)
+    df * Cosine.new(f)
+  end
+end
+
+class Cosine < Composite
+  @@types[:cos] = self
+
+  def self.compute_value(a)
+    Math.cos(a)
+  end
+
+  def self.compute_derivative(f, df)
+    df * -Sine.new(f)
+  end
+end
