emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Delimited continuations


From: Stefan Monnier
Subject: Re: Delimited continuations
Date: Mon, 11 Dec 2017 11:47:01 -0500
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/27.0.50 (gnu/linux)

[ For some reason, while I had no trouble getting an intuitive
  understanding of continuations and can happily write and reason
  about CPS style code, I must admit that I still haven't managed to
  really wrap my head around delimited continuations.
  You've been warned.  ]

> (reset (lambda (p)
>          (+ (+ 1 2)
>             (shift p (lambda (k) (funcall k 1))))))
[...]
> (+ 1 2) is executed twice.  I think this isn't necessarily so?

Right, but since (+ 1 2) is pure the problem is minor (and also because
whether (+ 1 2) was already computed or not depends on evaluation order
of arguments, which is defined in Elisp but would still be within the
scope of "acceptable quirks" in my book if it's not 100% obeyed).

Things get more interesting with side-effects:

   (defvar fwdc nil)
   (reset (λ (p)
      (if fwdl 3
        (setq fwdc t)
        (shift p (λ (k) (k 5))))))

since we end up re-computing the `if` test and hence not using the `5`
provided to `k`.  I think this case is a clear "bug" (because, IIUC,
(shift _ (λ (k) (k v))) should be equivalent to just `v`).

BTW, John:
>   (defun shift (k entry)
>     (if (eq (nth 0 k) 'outer)
>         (throw (nth 1 k)
>                (funcall entry #'(lambda (val)
>                                   (funcall (nth 2 k)
>                                            (list 'inner val)))))
>       (nth 1 k)))

It means that `entry` is evaluated within the dynamic context of `shift`
rather than within the dynamic context of `reset` (because you call
`entry` before calling `throw`).

This has a clear downside: we use extra stack space during evaluation of
`entry` (the extra stack space is equal to the stack space used between
`reset` and `shift`).  But I guess this is not too terrible.

It also means that dynamic-bindings (and other unwind-protects such as
with-current-buffer) applied within `k` up to now will still be active
during evaluation of `entry`.  Whether that's The Right Thing or not is
a good question but is beyond what my poor brain can take right now.


        Stefan




reply via email to

[Prev in Thread] Current Thread [Next in Thread]