Ивайло обнови решението на 13.11.2012 11:13 (преди около 12 години)
+
+module Interpetator
+
+ # ======================
+ # Environment
+ # ======================
+
+ module Core #; end
+ end
+
+ class Number #; end
+ end
+ class Variable #; end
+ end
+
+ class Expression #; end
+ end
+ class Unary < Expression #; end
+ end
+ class Binary < Expression #; end
+ end
+
+ # ======================
+ # Parse data
+ # ======================
+
+ module PARSE
+ TYPES = {
+ :number => Interpetator::Number ,
+ :variable => Interpetator::Variable,
+ }
+
+ OPERATORS = {
+ :unary => {
+ :+ => Interpetator::Unary,
+ :- => Interpetator::Unary,
+ :sin => Interpetator::Unary,
+ :cos => Interpetator::Unary,
+ },
+
+ :binary => {
+ :+ => Interpetator::Binary,
+ :- => Interpetator::Binary,
+ :* => Interpetator::Binary,
+ }
+ }
+ end
+
+ # ======================
+ # Other data
+ # ======================
+
+ LENGTH_TO_OPERATOR_TYPE = {
+ 2 => :unary ,
+ 3 => :binary,
+ }
+
+ # ======================
+ # Builder
+ # ======================
+
+ def self.build(syntax_tree)
+ if PARSE::TYPES.has_key? syntax_tree.first
+ type = PARSE::TYPES[syntax_tree.first]
+ value = syntax_tree.last
+
+ return type.new(value)
+ end
+
+ operation = syntax_tree .fetch 0
+ operation_type = LENGTH_TO_OPERATOR_TYPE .fetch syntax_tree.length
+ operation_type_list = PARSE::OPERATORS .fetch operation_type
+ operation_class = operation_type_list .fetch operation
+
+ operands = syntax_tree.slice(1..-1).map {|operand| build operand}
+
+ operation_class.new operation, *operands
+ end
+
+ # ======================
+ # Core
+ # ======================
+
+ # common functionality for all the atoms ...
+
+ module Core
+ def evaluate(scope = {})
+ calculate(scope).value
+ end
+
+ def calculate(scope = {})
+ self
+ end
+
+ def simplify
+ self
+ end
+ end
+
+ # ======================
+ # Operators
+ # ======================
+
+ module BaseOperators
+ def -@
+ self.class.new self.value.send :-@
+ end
+
+ def +@
+ self.class.new self.value.send :+@
+ end
+
+ def +(other)
+ self.class.new self.value + other.value
+ end
+
+ def -(other)
+ self.class.new self.value - other.value
+ end
+
+ def *(other)
+ self.class.new self.value * other.value
+ end
+ end
+
+ module MathOperators
+ def sin
+ self.class.new Math.sin @value
+ end
+
+ def cos
+ self.class.new Math.cos @value
+ end
+ end
+
+ # ======================
+ # Variables
+ # ======================
+
+ class Variable
+ include Core
+
+ attr_reader :name
+
+ def initialize(name)
+ @name = name
+ end
+
+ def calculate(scope = {})
+ unless scope[@name]
+ throw 'Undefined variable "' + @name.to_s + '"'
+ end
+
+ Number.new scope[@name]
+ end
+
+ def derive(var)
+ Number.new var == @name ? 1 : 0
+ end
+
+ def ==(other)
+ other.class == self.class and
+ other.name == self.name
+ end
+
+ def to_s
+ @name.to_s
+ end
+ end
+
+ # ======================
+ # Types
+ # ======================
+
+ class Number
+ include Core
+ include BaseOperators
+ include MathOperators
+
+ attr_reader :value
+
+ def initialize(value)
+ @value = value
+ end
+
+ def derive(var)
+ self.class.new 0
+ end
+
+ def ==(other)
+ other.class == self.class and
+ other.value == self.value
+ end
+
+ def to_s
+ @value.to_s
+ end
+ end
+
+ # ======================
+ # Expressions
+ # ======================
+
+ class Expression
+ include Core
+ end
+
+ class Unary < Expression
+ attr_reader :operator, :operand
+
+ OPERATORS_MAP = {
+ :+ => :+@,
+ :- => :-@,
+ }
+
+ DERIVE_RULES = {
+ :+@ => lambda do |operand, var|
+ Unary.new(:+@, operand.derive(var)).simplify
+ end,
+
+ :-@ => lambda do |operand, var|
+ Unary.new(:-@, operand.derive(var)).simplify
+ end,
+
+ :sin => lambda do |operand, var|
+ Binary.new(:+, operand.derive(var), Unary.new(:cos, operand)).simplify
+ end,
+
+ :cos => lambda do |operator, var|
+ Binary.new(:+, operand.derive(var), Unary.new(:sin, operand)).simplify
+ end,
+ }
+
+ SIMPLIFICATIONS = {
+ :number => lambda do |expression|
+ return expression.calculate if expression.operand.is_a? Number
+ end,
+
+ :+ => lambda do |expression|
+ return expression.operand if expression.operator == :+
+ end,
+ }
+
+ def initialize(operator, operand)
+ @operator = OPERATORS_MAP.fetch operator, operator
+ @operand = operand
+ end
+
+ def ==(other)
+ other.class == self.class and
+
+ other.operator== self.operator and
+ other.operand == self.operand
+ end
+
+ def calculate(scope = {})
+ @operand.calculate(scope).send @operator
+ end
+
+ def simplify
+ SIMPLIFICATIONS.each do |name, try_to_simplify|
+ simplified = try_to_simplify.call(self)
+
+ return simplified.simplify if simplified
+ end
+
+ self.class.new @operator, @operand.simplify
+ end
+
+ def derive(var)
+ DERIVE_RULES[operator].call operand, var
+ end
+
+ def to_s
+ "#{operator.to_s}(#{operand.to_s})"
+ end
+ end
+
+ class Binary < Expression
+ attr_reader :operator, :left_operand, :right_operand
+
+ DERIVE_RULES = {
+ :+ => lambda do |left_operand, right_operand, var|
+ Binary.new(:+, left_operand.derive(var), right_operand.derive(var)).simplify
+ end,
+
+ :- => lambda do |left_operand, right_operand, var|
+ DERIVE_RULES[:+].call left_operand, Unary.new(:-, right_operand)
+ end,
+
+ :* => lambda do |left_operand, right_operand, var|
+ Binary.new(
+ :+,
+ Binary.new(:*, left_operand.derive(var), right_operand),
+ Binary.new(:*, left_operand, right_operand.derive(var)),
+ ).simplify
+ end,
+ }
+
+ SIMPLIFICATIONS = {
+ :numbers => lambda do |expression|
+ return expression.calculate if
+ expression.left_operand .is_a? Number and
+ expression.right_operand.is_a? Number
+ end,
+
+ :variables => lambda do |expression|
+ return Number.new(0) if
+ expression.left_operand .is_a? Variable and
+ expression.right_operand.is_a? Variable and
+ expression.operator == :-
+ end,
+
+ :number_expression => lambda do |expression|
+ test_num = Number.new 13
+ left = expression.left_operand
+ right = expression.right_operand
+
+ unless left.is_a? Number and not right.is_a? Number
+ return
+ end
+
+ return case Binary.new( expression.operator, left, test_num ).calculate
+ when test_num then right
+ when left then left
+ end
+ end,
+
+ :expression_number => lambda do |expression|
+ return SIMPLIFICATIONS[:number_expression].call Binary.new(
+ expression.operator, expression.right_operand, expression.left_operand
+ )
+ end,
+ }
+
+ def initialize(operator, left_operand, right_operand)
+ @operator = operator
+ @left_operand = left_operand
+ @right_operand = right_operand
+ end
+
+ def ==(other)
+ other.class == self.class and
+
+ other.operator == self.operator and
+ other.left_operand == self.left_operand and
+ other.right_operand == self.right_operand
+ end
+
+ def calculate(scope = {})
+ @left_operand.calculate(scope).send @operator, @right_operand.calculate(scope)
+ end
+
+ def simplify
+ SIMPLIFICATIONS.each do |name, try_to_simplify|
+ simplified = try_to_simplify.call(self)
+
+ return simplified.simplify if simplified
+ end
+
+ simplified = self.class.new(
+ @operator,
+ @left_operand .simplify,
+ @right_operand.simplify,
+ )
+ if simplified == self then simplified else simplified.simplify end
+ end
+
+ def derive(var)
+ DERIVE_RULES[operator].call(left_operand, right_operand, var).simplify
+ end
+
+ def to_s
+ "(#{left_operand.to_s} #{operator.to_s} #{right_operand.to_s})"
+ end
+ end
+end
+
+Expr = Interpetator