For background information, see this blog post.
Implements delimited continuations in Ruby. This is a direct port of Oleg Kselyov's Scheme implementation.
This is an experiment. Ruby continuations are considered harmful. By the way, I want to take a minute to point out that this talk was at something called "Continuation Fest 2008", and calls Matz out for being a "criminal."
TL;DR: Don't use this for anything "serious."
Add this line to your application's Gemfile:
gem 'delimr'
And then execute:
$ bundle
Or install it yourself as:
$ gem install delimr
TODO: make this clearer
Delimited continuations can be a bit tricky. Basically, DelimR.prompt
takes a block and marks the boundary of the continuation. Inside DelimR.prompt
, you can call DelimR.control
which takes a block with a single argument. That argument is a function which represents the rest of the computation around the DelimR.control
block. The results of the DelimR.control
block, or of calling the continuation, will be returned to where the DelimR.prompt
was declared.
# k represents the computation outside of it
DelimR.prompt { 1 + DelimR.control { |k| k.call(3) } + 7}
# => 11
# If we don't call k, the computation is lost, and simply the value is returned
DelimR.prompt { 1 + DelimR.control { |k| 3 } + 7}
# => 3
# Delmited computations are composable! We can keep applying k to itself
DelimR.prompt { 1 + DelimR.control { |k| k.call(k.call(3)) } + 7}
# (1 + (1 + 3 + 7) + 7)
# => 19
Back in 1.8.7, Ruby core had an implementation of generators using plain old continuations. You can see it here.
Below, we implement Python style generators using delimited continuations.
class Generator
def initialize(&block)
@results = []
DelimR.prompt do
block.call(self)
end
end
def next
r = @results.pop
if r.nil?
raise "Iterator finished"
end
@k.call(nil)
r
end
def yield(result)
@results << result
DelimR.control do |k|
@k = k
end
end
end
and use it:
counter = Generator.new do |g|
ctr = 0
while true
g.yield(ctr)
ctr += 1
end
end
counter.next
# => 0
counter.next
# => 1
counter.next
# => 2
# ...
For more information on delimited continuations
- Fork it ( https://github.com/[my-github-username]/delimr/fork )
- Create your feature branch (
git checkout -b my-new-feature
) - Commit your changes (
git commit -am 'Add some feature'
) - Push to the branch (
git push origin my-new-feature
) - Create a new Pull Request