On 05/14/2012 04:26 PM, Asumu Takikawa wrote:
Hi all,
Here is a code snippet that uses both delimited continuations and
parameters (translated from the paper "Delimited Dynamic Binding"[1]):
#lang racket
(require racket/control)
(define p (make-parameter 0))
(define r (make-parameter 0))
((λ (f)
(parameterize ([p 2])
(parameterize ([r 20])
(f 0))))
(parameterize ([p 1])
(reset
(parameterize ([r 10])
((λ (x) (+ (p) (r)))
(shift f f))))))
If you run this, it produces 11. The authors of [1] argue that it should
return 12, namely because it follows the principle that "the dynamic
bindings in scope are those in the context".
That makes some sense, considering that when you eventually get to the
call (f 0) in the first lambda, your context looks like
(parameterize ([p 2])
(parameterize ([r 20])
(f 0)))
where f = (λ (y)
(parameterize ([r 10])
((λ (x) (+ (p) (r)))
y)))
according to shift/reset semantics. From this context, p = 2, r = 10
could make sense.
That said, I don't really have an intuition for what semantics for
dynamic binding& delimited control is useful. Is there a pragmatic
reason for why Racket's parameters and delimited control interact in
this fashion?
Racket contexts don't store individual parameter values, they store
entire *parameterizations* (which effectively contain the values of all
parameters). So f captures the parameterization {p=1, r=10}. When f is
called, it restores the entire parameterization, overriding the existing
mapping {p=2, r=20} at the call site.
Jay's "mark parameter" library (at unstable/markparam) provides
semantics that are probably closer to what you expect. (Except, IIRC,
not inherited across threads as parameters are.)
Ryan
____________________
Racket Users list:
http://lists.racket-lang.org/users