Skip to content

Instantly share code, notes, and snippets.

@lfborjas
Created March 28, 2011 11:18
Show Gist options
  • Save lfborjas/890302 to your computer and use it in GitHub Desktop.
Save lfborjas/890302 to your computer and use it in GitHub Desktop.
Examples of continuations
class Array
def one_at_a_time
control_state = lambda do |ret|
each do |elem|
callcc do |resume|
control_state = lambda do |r|
resume.call r
end
ret.call elem
end
end
ret.call :you_fell
end
lambda { callcc {|k| control_state.call(k)} }
end
def rest
self.slice 1..-1
end
def tree_generator
caller = nil
generate_leaves = lambda do
loop = lambda do |tree|
if tree.is_a?(Array) and tree.empty?
nil
elsif tree.is_a? Array
loop.call tree.first
loop.call tree.rest
else
callcc do |rest_of_tree|
generate_leaves = lambda{rest_of_tree.call(:resume)}
caller.call tree
end
end
end
loop.call(self)
end
lambda do
callcc do |k|
caller = k
generate_leaves.call
end
end
end
def same_fringe?(o)
gen1 = self.tree_generator
gen2 = o.tree_generator
loop do
leaf1 = gen1.call
leaf2 = gen2.call
if leaf1 == leaf2
if leaf1.nil?
return true
end
else
return false
end
end
end
#was trying to do this:
#http://www.ccs.neu.edu/home/dorai/t-y-scheme/t-y-scheme-Z-H-1.html#node_toc_node_sec_13.4
#but just cant find a way to implement the resume method well... I tried instance methods,
#and class methods, but I can't find a way to access the current coroutine and the other one
#in the blocks passed to new!!!!
def eqfringe?(o)
#LOOK MA! A letrec simulation!!!
#used lambda to mimic lazy evaluation and can now define leafer1 and leafer2 in terms of something
#that doesn't exist yet!
matcher = nil
letrec = {
:leafer1 => lambda{make_gen(self, matcher)},
:leafer2 => lambda{make_gen(o, matcher)}
}
matcher = lambda{make_matcher(letrec[:leafer1].call, letrec[:leafer2].call)}
matcher.call.invoke
end
private
def make_matcher(tree_cor1, tree_cor2)
Coroutine.new do
rval = false
loop do
leaf1 = Coroutine.resume c, tree_cor1
leaf2 = Coroutine.resume c, tree_cor2
if leaf1 == leaf2
if leaf1.nil? then rval = true; break end
else
break
end
end
rval
end
end
def make_gen(t, matcher)
Coroutine.new do
loop = lambda do |tree|
if tree.is_a?(Array) and tree.empty?
nil
elsif tree.is_a? Array
loop.call tree.first
loop.call tree.rest
else
Coroutine.resume self, matcher, tree
end
end
loop.call(t)
end
end
end
class Coroutine
attr_accessor :resume, :control_state
def initialize(&body)
@control_state = proc &body
end
def invoke(v=nil)
@control_state.call v
end
def self.resume(s, c, v=nil)
callcc do |k|
s.control_state = k
c.invoke v
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment