Skip to content

Instantly share code, notes, and snippets.

@GeertVL-zz
Created September 26, 2013 13:40
Show Gist options
  • Save GeertVL-zz/6714358 to your computer and use it in GitHub Desktop.
Save GeertVL-zz/6714358 to your computer and use it in GitHub Desktop.
Exercise for 'Understanding Computation'
## Arrived at page 52 (Statements)
class Number < Struct.new(:value)
def to_s
value.to_s
end
def inspect
"<<#{self}>>"
end
def reducible?
false
end
def evaluate(environment)
self
end
def to_ruby
"-> e { #{value.inspect} }"
end
end
class Add < Struct.new(:left, :right)
def to_s
"#{left} + #{right}"
end
def inspect
"<<#{self}>>"
end
def reducible?
true
end
def reduce(environment)
if left.reducible?
Add.new(left.reduce(environment), right)
elsif right.reducible?
Add.new(left, right.reduce(environment))
else
Number.new(left.value + right.value)
end
end
def evaluate(environment)
Number.new(left.evaluate(environment).value + right.evaluate(environment).value)
end
def to_ruby
"-> e { (#{left.to_ruby}).call(e) + (#{right.to_ruby}).call(e) }"
end
end
class Subtract < Struct.new(:left, :right)
def to_s
"#{left} - #{right}"
end
def inspect
"<<#{self}>>"
end
def reducible?
true
end
def reduce(environment)
if left.reducible?
Subtract.new(left.reduce(environment), right)
elsif right.reducible?
Subtract.new(left, right.reduce(environment))
else
Number.new(left.value - right.value)
end
end
def evaluate(environment)
Number.new(left.evaluate(environment).value - right.evaluate(environment).value)
end
def to_ruby
"-> e { (#{left.to_ruby}).call(e) - (#{right.to_ruby}).call(e) }"
end
end
class Divide < Struct.new(:left, :right)
def to_s
"#{left} / #{right}"
end
def inspect
"<<#{self}>>"
end
def reducible?
true
end
def reduce(environment)
if left.reducible?
Divide.new(left.reduce(environment), right)
elsif right.reducible?
Divide.new(left, right.reduce(environment))
else
Number.new(left.value / right.value)
end
end
def evaluate(environment)
Number.new(left.evaluate(environment).value / right.evaluate(environment).value)
end
def to_ruby
"-> e { (#{left.to_ruby}).call(e) / (#{right.to_ruby}).call(e) }"
end
end
class Multiply < Struct.new(:left, :right)
def to_s
"#{left} * #{right}"
end
def inspect
"<<#{self}>>"
end
def reducible?
true
end
def reduce(environment)
if left.reducible?
Multiply.new(left.reduce(environment), right)
elsif right.reducible?
Multiply.new(left, right.reduce(environment))
else
Number.new(left.value * right.value)
end
end
def evaluate(environment)
Number.new(left.evaluate(environment).value * right.evaluate(environment).value)
end
def to_ruby
"-> e { (#{left.to_ruby}).call(e) * (#{right.to_ruby}).call(e) }"
end
end
class Boolean < Struct.new(:value)
def to_s
value.to_s
end
def inspect
"<<#{self}>>"
end
def reducible?
false
end
def evaluate(environment)
self
end
def to_ruby
"-> e { #{value.inspect} }"
end
end
class LessThan < Struct.new(:left, :right)
def to_s
"#{left} < #{right}"
end
def inspect
"<<#{self}>>"
end
def reducible?
true
end
def reduce(environment)
if left.reducible?
LessThan.new(left.reduce(environment), right)
elsif right.reducible?
LessThan.new(left, right.reduce(environment))
else
Boolean.new(left.value < right.value)
end
end
def evaluate(environment)
Number.new(left.evaluate(environment).value < right.evaluate(environment).value)
end
def to_ruby
"-> e { (#{left.to_ruby}).call(e) < (#{right.to_ruby}).call(e) }"
end
end
class Variable < Struct.new(:name)
def to_s
name.to_s
end
def inspect
"<<#{self}>>"
end
def reducible?
true
end
def reduce(environment)
environment[name]
end
def evaluate(environment)
environment[name]
end
def to_ruby
"-> e { e[#{name.inspect}] }"
end
end
class DoNothing
def to_s
'do-nothing'
end
def inspect
"<<#{self}>>"
end
def ==(other_statement)
other_statement.instance_of(DoNothing)
end
def reducible?
false
end
def evaluate(environment)
environment
end
end
class Assign < Struct.new(:name, :expression)
def to_s
"#{name} = #{expression}"
end
def inspect
"<<#{self}>>"
end
def reducible?
true
end
def reduce(environment)
if expression.reducible?
[Assign.new(name, expression.reduce(environment)), environment]
else
[DoNothing.new, environment.merge({ name => expression })]
end
end
def evaluate(environment)
environment.merge({ name => expression.evaluate(environment) })
end
class If < Struct.new(:condition, :consequence, :alternative)
def to_s
"if (#{condition}) { #{consequence} } else { #{alternative} }"
end
def inspect
"<<#{self}>>"
end
def reducible?
true
end
def reduce(environment)
if condition.reducible?
[If.new(condition.reduce(environment), consequence, alternative), environment]
else
case condition
when Boolean.new(true)
[consequence, environment]
when Boolean.new(false)
[alternative, environment]
end
end
end
def evaluate(environment)
case condition.evaluate(environment)
when Boolean.new(true)
consequence.evaluate(environment)
when Boolean.new(false)
alternative.evaluate(environment)
end
end
end
class Sequence < Struct.new(:first, :second)
def to_s
"#{first}; #{second}"
end
def inspect
"<<#{self}>>"
end
def reducible?
true
end
def reduce(environment)
case first
when DoNothing.new
[second, environment]
else
reduced_first, reduced_environment = first.reduce(environment)
[Sequence.new(reduced_first, second), reduced_environment]
end
end
def evaluate(environment)
second.evaluate(first.evaluate(environment))
end
end
class While < Struct.new(:condition, :body)
def to_s
"while (#{condition}) { #{body} }"
end
def inspect
"<<#{self}>>"
end
def reducible?
true
end
def reduce(environment)
[If.new(condition), Sequence.new(body, self), DoNothing.new), environment]
end
def evaluate(environment)
case condition.evaluate(environment)
when Boolean.new(true)
evaluate(body.evaluate(environment))
when Boolean.new(false)
environment
end
end
end
class Machine < Struct.new(:expression, :environment)
def step
self.statement, self.environment = statement.reduce(environment)
end
def run
while statement.reducible?
puts "#{statement}, #{environment}"
step
end
puts "#{statement}, #{environment}"
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment