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 racket-users+unsubscr...@googlegroups.com.
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