technology from back to front

Delimited dynamic variables from call/cc

I’m prepared to own up to my biases. I like delimited continuations. I like zippers. I like getting halfway through my work, shelving my work for a time, and coming back to it later.

We’ve seen the relationship between resumable exceptions and delimited dynamic variables before, but what about languages where you don’t have direct access to the call stack? Let’s implement delimited dynamic variables by implementing resumable exceptions with call/cc (obligatory mention of why call/cc’s a bad idea). So what’s that look like in Ruby, then?

require 'continuation'

module ResumableExceptions
  def raise(*args)
    # When we raise an exception, store a reference to the current continuation.
    callcc do |continuation|
      begin
        super
      rescue Exception => e
        e.continuation = continuation
        super(e)
      end
    end
  end
end

class Exception
  attr_accessor :continuation

  def resume(new_val)
    # When we resume, we stuff new_val into the continuation, effectively
    # turning the #raise call into a value-returning expression.
    continuation.call(new_val)
  end
end

class Object
  include ResumableExceptions
end

class DelimDynVar < Exception
  def initialize(default_val)
    @default_val = default_val
  end

  def dlet(new_val, &blk)
    begin
      blk.call
    rescue self => e
      e.resume(new_val)
    end
  end

  def dref
    val = raise self
    if val then
      val
    else
      @default_val
    end
  end
end

p = DelimDynVar.new(1)
q = DelimDynVar.new(:a)
q.dlet(:b) {
                  # What we expect to see:
  puts q.dref     #   b
  p.dlet(2) {
    puts p.dref   #   2
    puts q.dref   #   b
    p.dlet(3) {
      puts p.dref #   3
    }
    puts p.dref   #   2
  }
}
p.dref            # Problematic, because outside of any dlet block, we
                  # raise an unhandled exception, and go boom.

And this produces:

b
2
b
3
2
foo.rb:8:in `block in raise': DelimDynVar (DelimDynVar)
        from foo.rb:6:in `
callcc'
        from foo.rb:6:in `raise'

        from foo.rb:45:in `dref'
        from foo.rb:59:in `
block (2 levels) in <main>'
        from foo.rb:38:in `call'

        from foo.rb:38:in `dlet'
        from foo.rb:58:in `
block in <main>'
        from foo.rb:38:in `call'

        from foo.rb:38:in `dlet'
        from foo.rb:56:in `
<main>'
by
Frank Shearar
on
31/08/13
  1. soren renner
    on 03/09/13 at 8:22 pm

    What language is this code?

  2. Frank Shearar
    on 05/09/13 at 11:01 am

    It’s in Ruby. I’ll update the article to make that clear.

 
 


− four = 5

2000-14 LShift Ltd, 1st Floor, Hoxton Point, 6 Rufus Street, London, N1 6PE, UK+44 (0)20 7729 7060   Contact us