unofficial mirror of guile-devel@gnu.org 
 help / color / mirror / Atom feed
From: Ian Price <ianprice90@googlemail.com>
To: Nala Ginrut <nalaginrut@gmail.com>
Cc: "Ludovic Courtès" <ludo@gnu.org>, guile-devel@gnu.org
Subject: Re: [PATCH] Move let/ec to top-level
Date: Sat, 06 Apr 2013 01:52:56 +0100	[thread overview]
Message-ID: <87bo9s8opj.fsf@Kagami.home> (raw)
In-Reply-To: <1365056340.2755.5.camel@Renee-desktop.suse> (Nala Ginrut's message of "Thu, 04 Apr 2013 14:19:00 +0800")

Nala Ginrut <nalaginrut@gmail.com> writes:

> +@deffn {Scheme Procedure} call/ec proc
> +'ec' stands for escape-continuation, or so-called 'one-shot' continuation.
> +@var{call/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}.
> +@end 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.

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

> +@example
> +(use-module (ice-9 control))
> +
> +(call/ec (lambda (return)
> +           (return 123)))
> +
> +(let/ec return (return 123))
> +@end 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"



  parent reply	other threads:[~2013-04-06  0:52 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-01-14 15:20 [PATCH] Move let/ec to top-level Nala Ginrut
2013-01-22 11:43 ` Andy Wingo
2013-03-27 21:14 ` Ludovic Courtès
2013-04-04  6:19   ` Nala Ginrut
2013-04-05 20:59     ` Ludovic Courtès
2013-04-06  0:52     ` Ian Price [this message]
2013-04-06  2:53       ` Nala Ginrut
2013-04-06  1:04     ` Ian Price
2013-04-06 13:38       ` Ludovic Courtès
2013-04-06  2:15     ` Ian Price
2013-04-06 13:41       ` Ludovic Courtès

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/guile/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87bo9s8opj.fsf@Kagami.home \
    --to=ianprice90@googlemail.com \
    --cc=guile-devel@gnu.org \
    --cc=ludo@gnu.org \
    --cc=nalaginrut@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).