Hello,

I have been playing with implementing algebraic effects using delimited 
control, and Dorai Sitaram’s `fcontrol` and `%` operators are a natural fit. 
For example, it’s straightforward to implement McCarthy’s `amb` operator using 
them:

  (define amb-tag (make-continuation-prompt-tag 'amb))

  ; -> none/c
  (define (fail) (fcontrol 'fail #:tag amb-tag))
  ; -> boolean?
  (define (choice) (fcontrol 'choice #:tag amb-tag))

  (define-syntax amb
    (syntax-rules ()
      [(_)          (fail)]
      [(_ e)        e]
      [(_ e0 e ...) (if (choice) e0 (amb e ...))]))

The whole point of algebraic effect handlers is that we can interpret the same 
effect multiple ways, and `%` makes that easy. For example, we can write one 
`amb` handler that returns only the first result and another one that returns 
all results:

  (define (run-amb/first proc)
    (% (proc)
       (λ (op k)
         (match op
           ['fail   #f]
           ['choice (or (run-amb/first (thunk (k #t)))
                        (run-amb/first (thunk (k #f))))]))
       #:tag amb-tag))

  (define (run-amb/all proc)
    (let go ([proc (thunk (list (proc)))])
      (% (proc)
         (λ (op k)
           (match op
             ['fail   '()]
             ['choice (append (go (thunk (k #t)))
                              (go (thunk (k #f))))]))
         #:tag amb-tag)))

This mostly works nicely, but the way it interacts with `dynamic-wind` leaves 
something to be desired:

  > (run-amb/first
      (thunk
        (dynamic-wind
          (thunk (displayln "--> in"))
          (thunk (+ (amb 1 2) (amb 3 4)))
          (thunk (displayln "<-- out")))))
  --> in
  <-- out
  --> in
  <-- out
  --> in
  <-- out
  4

This is a little bit silly, since control is jumping out of the extent of 
`dynamic-wind` only to immediately re-enter it. If `dynamic-wind` is being used 
to guard access to a lock or pooled resource, we probably don’t want it to be 
released and reacquired on every call to `amb`.

However, I’m not sure how I can rearrange things to make that possible. I can’t 
just store the current `amb` handler in a parameter/continuation mark because 
it really does need to extend the continuation of the whole computation. Is 
there any way to do that with Racket’s continuation machinery, or would I need 
to use mutable state to imperatively extend a list of continuations maintained 
by the current handler? Also, is this kind of thing discussed anywhere in the 
literature?

Thanks,
Alexis

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/racket-users/9EEF26EF-C60C-49B7-92D4-27648C111213%40gmail.com.

Reply via email to