Стоян обнови решението на 14.11.2012 11:24 (преди около 12 години)
+class Expr
+ def Expr.build(input)
+ case input.first
+ when :number then Number.new input.drop(1).first
+ when :variable then Variable.new input.drop(1).first
+ when :+ then (build(input.drop(1).first) + build(input.last))
+ when :* then (build(input.drop(1).first) * build(input.last))
+ when :- then Negation.new build(input.drop(1).first)
+ when :sin then Sine.new build(input.drop(1).first)
+ when :cos then Cosine.new build(input.drop(1).first)
+ end
+ end
+
+ def*(other)
+ Multiplication.new(self, other)
+ end
+
+ def+(other)
+ Addition.new(self, other)
+ end
+
+ def-@
+ Negation.new(self)
+ end
+end
+
+class Unary < Expr
+ attr_reader :expression
+
+ def initialize(expression)
+ @expression = expression
+ end
+
+ def==(other)
+ return false if self.class != other.class
+ self.expression == other.expression
+ end
+
+ def exact?
+ @expression.exact?
+ end
+end
+
+class Binary < Expr
+ attr_reader :left_expression, :right_expression
+
+ def initialize(left_expression, right_expression)
+ @left_expression = left_expression
+ @right_expression = right_expression
+ end
+
+ def==(other)
+ return false if self.class != other.class
+ self.left_expression == other.left_expression and
+ self.right_expression == other.right_expression
+ end
+
+ def exact?
+ @left_expression.exact? and @right_expression.exact?
+ end
+end
+
+class Addition < Binary
+ def derive(variable)
+ (left_expression.derive(variable) + right_expression.derive(variable)).simplify
+ end
+
+ def evaluate(environment = {})
+ @left_expression.evaluate(environment) + @right_expression.evaluate(environment)
+ end
+
+ def simplify
+ return Number.new(@left_expression.evaluate + right_expression.evaluate) if exact?
+ return @right_expression.simplify if @left_expression.simplify == Number.new(0)
+ return @left_expression.simplify if @right_expression.simplify == Number.new(0)
+ return @left_expression.simplify + @right_expression.simplify
+ end
+end
+
+class Multiplication < Binary
+ def derive(variable)
+ ((left_expression.derive(variable) * right_expression) +
+ (left_expression * right_expression.derive(variable))).simplify
+ end
+
+ def evaluate(environment = {})
+ @left_expression.evaluate(environment) * @right_expression.evaluate(environment)
+ end
+
+ def simplify
+ return Number.new(@left_expression.evaluate * right_expression.evaluate) if exact?
+ return @right_expression.simplify if @left_expression.simplify == Number.new(1)
+ return @left_expression.simplify if @right_expression.simplify == Number.new(1)
+ return Number.new(0) if @left_expression.simplify == Number.new(0) or
+ @right_expression.simplify == Number.new(0)
+ return @left_expression.simplify * @right_expression.simplify
+ end
+end
+
+class Number < Unary
+ def derive(variable)
+ Number.new(0)
+ end
+
+ def evaluate(environment = {})
+ @expression
+ end
+
+ def simplify
+ self
+ end
+
+ def exact?
+ true
+ end
+
+end
+
+class Variable < Unary
+ def derive(variable)
+ @expression == variable ? Number.new(1) : Number.new(0)
+ end
+
+ def evaluate(environment = {})
+ environment.fetch(@expression)
+ end
+
+ def simplify
+ self
+ end
+
+ def exact?
+ false
+ end
+end
+
+class Negation < Unary
+ def derive(variable)
+ @expression.derive(variable).simplify
+ end
+
+ def evaluate(environment = {})
+ -(@expression.evaluate environment)
+ end
+
+ def simplify
+ -(@expression.evaluate)
+ end
+end
+
+class Sine < Unary
+ def derive(variable)
+ (@expression.derive(variable) * (Cosine.new @expression)).simplify
+ end
+
+ def evaluate(environment = {})
+ Math.sin(@expression.evaluate environment)
+ end
+
+ def simplify
+ Number.new @expression.evaluate
+ end
+end
+
+class Cosine < Unary
+ def derive
+ (@expression.derive(variable) * (-(Sine.new @expression))).simplify
+ end
+
+ def evaluate(environment = {})
+ Math.cos(@expression.evaluate environment)
+ end
+
+ def simplify
+ Number.new @expression.evaluate
+ end
+end