Skip to content

Instantly share code, notes, and snippets.

@gotascii
Created October 25, 2010 22:46
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save gotascii/645951 to your computer and use it in GitHub Desktop.
Save gotascii/645951 to your computer and use it in GitHub Desktop.
continuations via blocks and exceptions
# I got this idea from http://mihai.bazon.net/blog/redis-client-library-javascript-node
# The technique relies on the fact that raising an exception clears the call stack.
# The context is passed along with a block attached to an exception.
# I thought it was brilliant js hackery so I decided to try my hand at it in ruby.
# I've also included some other stack-dependent implementations.
# straight recursion, not quite a tail-call
# I can't go above 8.1k without stack error
def rsum(num)
if num == 0
0
else
num + rsum(num - 1)
end
end
# tail-call block based recursion
# I can't go above 7.6k without stack error
def crsum(num, total = 0, &block)
if num == 0
yield total
else
crsum(num - 1, num + total, &block)
end
end
# Using blocks and exceptions to clear call stack
class Beer < RuntimeError
attr_accessor :block
def initialize(&block)
@block = block
end
end
def cheers!(&block)
raise Beer.new(&block)
end
def cc(&block)
loop do
begin
block.call
break
rescue Beer => beer
block = beer.block
end
end
end
def sum(num, total = 0, &block)
if num == 0
yield total
else
cheers! { sum(num - 1, num + total, &block) }
end
end
cc { sum(100) {|t| puts t} }
# Run this block in irb.
# I got up to 100k and it still works!
# cc { sum(1000) {|total| puts total} }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment