Емил обнови решението на 13.11.2012 00:05 (преди около 12 години)
+class Expr
+ def self.build(expression)
+ case expression[0]
+ when :number then Number.new(expression[1])
+ when :variable then Variable.new(expression[1])
+ when :+ then Addition.new(build(expression[1]), build(expression[2]))
+ when :* then Multiplication.new(build(expression[1]), build(expression[2]))
+ when :- then Negation.new(build(expression[1]))
+ when :sin then Sine.new(build(expression[1]))
+ when :cos then Cosine.new(build(expression[1]))
+ end
+ end
+
+ def *(other)
+ if self == Zero || other == Zero
+ Number.new(0)
+ elsif self == One
+ other
+ elsif other == One
+ self
+ else
+ Multiplication.new(self, other)
+ end
+ end
+
+ def +(other)
+ if self == Zero
+ other
+ elsif other == Zero
+ self
+ else
+ Addition.new(self, other)
+ end
+ end
+
+ def -@
+ if self == Zero
+ @parameter
+ else
+ Negation.new(self)
+ end
+ end
+end
+
+class Unary < Expr
+ attr_accessor :parameter
+
+ def initialize(parameter)
+ @parameter = parameter
+ end
+
+ def ==(other)
+ @parameter == other.parameter
+ end
+
+ def exact?
+ @parameter.exact?
+ end
+end
+
+class Binary < Expr
+ attr_accessor :parameter1, :parameter2
+
+ def initialize(parameter1, parameter2)
+ @parameter1, @parameter2 = parameter1, parameter2
+ end
+
+ def ==(other)
+ @parameter1 == other.parameter1 && @parameter2 == other.parameter2
+ end
+
+ def exact?
+ @parameter1.exact? & @parameter2.exact?
+ end
+end
+
+class Number < Unary
+ def evaluate(environment = {})
+ @parameter
+ end
+
+ def simplify
+ self
+ end
+
+ def exact?
+ true
+ end
+
+ def derive(variable)
+ Number.new(0)
+ end
+end
+
+class Addition < Binary
+ def evaluate(environment = {})
+ @parameter1.evaluate(environment) + @parameter2.evaluate(environment)
+ end
+
+ def simplify
+ if exact?
+ Number.new(evaluate)
+ else
+ @parameter1.simplify + @parameter2.simplify
+ end
+ end
+
+ def derive(variable)
+ (@parameter1.derive(variable) + @parameter2.derive(variable)).simplify
+ end
+end
+
+class Negation < Unary
+ def evaluate(environment = {})
+ -@parameter.evaluate(environment)
+ end
+
+ def simplify
+ if exact?
+ Number.new(evaluate)
+ else
+ -@parameter.simplify
+ end
+ end
+
+ def derive(variable)
+ (-@parameter.derive(variable)).simplify
+ end
+end
+
+class Multiplication < Binary
+ def evaluate(environment = {})
+ @parameter1.evaluate(environment) * @parameter2.evaluate(environment)
+ end
+
+ def simplify
+ if exact?
+ Number.new(evaluate)
+ else
+ @parameter1.simplify * @parameter2.simplify
+ end
+ end
+
+ def derive(variable)
+ result = @parameter1.derive(variable) * @parameter2 + @parameter1 * @parameter2.derive(variable)
+ result.simplify
+ end
+end
+
+class Variable < Unary
+ def evaluate(environment = {})
+ environment.values_at(@parameter)[0]
+ end
+
+ def simplify
+ self
+ end
+
+ def exact?
+ false
+ end
+
+ def derive(variable)
+ if variable == @parameter
+ Number.new(1)
+ else
+ Number.new(0)
+ end
+ end
+end
+
+class Sine < Unary
+ def evaluate(environment = {})
+ Math.sin @parameter.evaluate(environment)
+ end
+
+ def simplify
+ if @parameter.exact?
+ Number.new(evaluate)
+ else
+ Sine.new(@parameter.simplify)
+ end
+ end
+
+ def derive(variable)
+ (@parameter.derive(variable) * Cosine.new(@parameter)).simplify
+ end
+end
+
+class Cosine < Unary
+ def evaluate(environment = {})
+ Math.cos @parameter.evaluate(environment)
+ end
+
+ def simplify
+ if @parameter.exact?
+ Number.new(evaluate)
+ else
+ Cosine.new(@parameter.simplify)
+ end
+ end
+
+ def derive(variable)
+ (@parameter.derive(variable) * (- Sine.new(@parameter))).simplify
+ end
+end
+
+Zero = Number.new(0)
+One = Number.new(1)
+
+p Expr.build([:cos, [:variable, :x]]).derive(:x)