leonoel / cloroutine

Coroutine support for clojure
Eclipse Public License 2.0
228 stars 10 forks source link

delimited continuations #15

Closed pbaille closed 4 years ago

pbaille commented 4 years ago

I was reading https://en.wikipedia.org/wiki/Delimited_continuation along with the delimited continuation guide of cloroutine.

I came accross some questions along the way. because the semantics of shift are different.

I've made that gist that tries to port the code of the wiki with cloroutine's delimited continuations: https://gist.github.com/pbaille/2b8d3427df830a71144d59554277fde9

any opinions or advices related to this will be welcome

thank you

leonoel commented 4 years ago

That's a fundamental limitation of any syntax-based coroutine implementation. cr can't rewrite code outside of its body, so as soon as the splitter symbol is wrapped into a plain function it's not workable anymore. (quoting the guide : we can't shift/reset across stack frames). core.async's go works the same way, javascript's generators as well.

It's not possible to achieve what you want without modifying the host platform. Your attempts work by accident, they will likely break in non-trivial situations and that's not something you should rely on. In my opinion, the less hacky way to fully emulate scheme-style shift/reset is to turn every shifting function into a macro, such that the code is inlined in the reset block instead of being wrapped in an opaque lambda. For instance :

(defmacro yield [x] `(let [x# ~x] (shift k# (cons x# (k# ())))))
(reset (yield 1) (yield 2) (yield 3))
#_=> (1 2 3)
pbaille commented 4 years ago

thank you a lot for your answer! (and for your really interesting work) The macro approach that you suggest is indead a better solution :)