guile-devel
[Top][All Lists]
Advanced

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

Re: [PATCH] Move let/ec to top-level


From: Ian Price
Subject: Re: [PATCH] Move let/ec to top-level
Date: Sat, 06 Apr 2013 01:52:56 +0100
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/23.3 (gnu/linux)

Nala Ginrut <address@hidden> writes:

> address@hidden {Scheme Procedure} call/ec proc
> +'ec' stands for escape-continuation, or so-called 'one-shot' continuation.
> address@hidden/ec} is equivalent to call-with-escape-continuation. 
> +A continuation obtained from call/ec is actually a kind of prompt. 
> @var{call/ec}
> +is often an easy replacement for @var{call/cc} to improve performance.
> +More details read 
> @uref{http://www.cs.indiana.edu/~bruggema/one-shots-abstract.html, 
> +Representing control in the presence of one-shot continuations}.
> address@hidden deffn
This isn't any good. It doesn't tell us what an escape continuation is,
it doesn't tell us how to use it, and it only hints at why you should
use them. Yeah, if you know what a continuation is "one-shot
continuation" isn't going to be a surprising definition, but we can do
better than that in Guile's manual.

Here is something closer to how I envision this section should be
written. I have not taken the liberty of texinfoifying it.

----
Often in Guile, you do not need the full unrestricted power of first
class continuations, you just want an escape.  For example, to break
out of multiplying a list of numbers, you might write

  (define (product list)
    (call-with-current-continuation
      (lambda (break)
        (let loop ((list list) (product 1))
          (cond ((null? list) product)
                ((zero? (car list)) (break 0))
                (else (loop (cdr list) (* (car list) product))))))))

In this case, it can be more transparent, and more efficient, to use a
restricted form of continuation, which we refer to as an escape (or
one-shot) continuation, that only permits you to call it once from to
escape from inside the body of the function.


Scheme Procedure call-with-escape-continuation proc
Scheme Procedure call/ec proc

Capture the current escape-only continuation, and call proc with this
continuation as its argument.  The return value(s) of this expression
are the value(s) returned by proc, or, the arguments passed to the
escape continuation if it is invoked.

If the escape continuation is invoked more than once, or it is invoked
after proc has returned, it is an $error.

call/ec is an alias for call-with-escape-continuation
----

I didn't check what error actually gets returned, so that bit needs
filled in.

In various parts of the manual, we mention that prompts should be used
for the situation of escapes.  We should probably hunt those down and
replace those with recommendations to use call/ec or let/ec.

> address@hidden {Scheme Syntax} let/ec k body
> +Equivalent to (call/ec (lambda (k) body ...)).
> address@hidden deffn
Missing ellipses in the function prototype. In Texinfo, you should be
using @dots{} rather than three periods for ellipses.

> address@hidden
> +(use-module (ice-9 control))
> +
> +(call/ec (lambda (return)
> +           (return 123)))
> +
> +(let/ec return (return 123))
> address@hidden example
Not a particularly convincing example, maybe drop it?

> +
> +(define %call/ec-prompt
> +  (make-prompt-tag))
You don't use this, so you can remove it.  If your intent was to reuse
the prompt so that you didn't have to do a gensym each time, beware,
this won't give the correct semantics for call/ec.

e.g.
(call/ec
  (lambda (outer)
    (call/ec
      (lambda (inner)
        (outer #f)))
    #t))

will return #t rather than #f

> +(define-syntax-rule (call/ec proc)
define rather than define-syntax-rule

> +  ;; aka. `call-with-escape-continuation'
Rather than an aka in a comment, maybe we should export this.  In the
example documentation given above, I've assumed this.

> +  (let ((tag (make-prompt-tag)))
> +    (call-with-prompt 
> +     tag
> +     (lambda ()
> +       (proc (lambda args (apply abort-to-prompt args))))
you are not aborting to the tag, but to the first of the args
(the dangers of copy-paste)

> +     (lambda (_ . args)
> +       (apply values args)))))
> +
> +(define-syntax-rule (let/ec k e e* ...)
> +  ;; aka. `let-escape-continuation'
Rather let-with-escape-continuation than let-escape-continuation, since
it's the same convention as with call/ec and call/cc (not that it
matters if we don't export it)

As an aside, we don't have a corresponding let/cc, but I suspect most
uses of it in practice would be replaced by let/ec.

> -(define-syntax-rule (let/ec k e e* ...)           ; TODO: move to core
> -  (let ((tag (make-prompt-tag)))
> -    (call-with-prompt
> -     tag
> -     (lambda ()
> -       (let ((k (lambda args (apply abort-to-prompt tag args))))
> -         e e* ...))
> -     (lambda (_ res) res))))
> -
> -
>  (define %future-prompt
>    ;; The prompt futures abort to when they want to wait for another
>    ;; future.
This isn't the only definition of let/ec in the Guile source code. I see
definitions in module/language/tree-il/peval.scm and
module/sxml/match.scm (as an aside, I notice match.scm makes the prompt
reuse mistake you almost did)

-- 
Ian Price -- shift-reset.com

"Programming is like pinball. The reward for doing it well is
the opportunity to do it again" - from "The Wizardy Compiled"



reply via email to

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