unofficial mirror of guile-devel@gnu.org 
 help / color / mirror / Atom feed
* when and unless
@ 2011-06-30 10:44 Andy Wingo
  2011-06-30 21:46 ` Ludovic Courtès
  2011-12-05 20:23 ` Andy Wingo
  0 siblings, 2 replies; 28+ messages in thread
From: Andy Wingo @ 2011-06-30 10:44 UTC (permalink / raw)
  To: guile-devel

I think we should add `when' and `unless' to the default environment.

They go like this:

  (define-syntax when
    (syntax-rules ()
      ((_ test then then* ...)
       (if test (begin then then* ... (if #f #f))))))

  (define-syntax unless
    (syntax-rules ()
      ((_ test else else* ...)
       (if (not test) (begin else else* ... (if #f #f))))))

These are pretty uncontroversial and common, and they make it easier to
read code, so let's do it.

The only argument I have heard against them is that "when" connotes some
connection with time, whereas "if" does not.  I agree with this
criticism, but "when" is sufficiently common that it shouldn't confuse
anyone, and in any case we have modules if someone feels strongly enough
to not want these bindings.

The trailing (if #f #f) is to indicate that the consequent expressions
are evaluated for effect, not for value, and the the return value(s) of
`when' and `unless' are not specified.  In the future we may cause
instances of (if #f #f) used for a value to emit a warning or an error.

Regards,

Andy
-- 
http://wingolog.org/



^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: when and unless
  2011-06-30 10:44 when and unless Andy Wingo
@ 2011-06-30 21:46 ` Ludovic Courtès
  2011-07-01  7:50   ` Andy Wingo
  2011-12-05 20:23 ` Andy Wingo
  1 sibling, 1 reply; 28+ messages in thread
From: Ludovic Courtès @ 2011-06-30 21:46 UTC (permalink / raw)
  To: guile-devel

Hello comrade!

Andy Wingo <wingo@pobox.com> skribis:

> I think we should add `when' and `unless' to the default environment.

[...]

> These are pretty uncontroversial

What?!

  http://lists.r6rs.org/pipermail/r6rs-discuss/2007-March/thread.html#1856

Here’s another argument: these macros are about writing imperative code,
which, as we all know, is Evil.  As such, they are unacceptable.

(Seriously though, I won’t use them but won’t complain either if they
land in Guile.)

Thanks,
Ludo’.




^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: when and unless
  2011-06-30 21:46 ` Ludovic Courtès
@ 2011-07-01  7:50   ` Andy Wingo
  2011-07-01 12:47     ` Ludovic Courtès
  0 siblings, 1 reply; 28+ messages in thread
From: Andy Wingo @ 2011-07-01  7:50 UTC (permalink / raw)
  To: Ludovic Courtès; +Cc: guile-devel

Hi :)

On Thu 30 Jun 2011 23:46, ludo@gnu.org (Ludovic Courtès) writes:

>   http://lists.r6rs.org/pipermail/r6rs-discuss/2007-March/thread.html#1856

Wow, forgot about that one ;)

> Here’s another argument: these macros are about writing imperative code,
> which, as we all know, is Evil.  As such, they are unacceptable.
>
> (Seriously though, I won’t use them but won’t complain either if they
> land in Guile.)

OK, cool.

One place you might want to use them though is in type checks for Scheme
code.  We currently don't do very much of that, but probably should in
the future.  As in:

  (define (parameter-fluid p)
    (unless (parameter? p) (wrong-type-arg p 'parameter))
    (struct-ref p 1))

The advantage of `unless' over `if' is that the wrong-type-arg is not
called in tail position, so the error message sees `parameter-fluid' on
the stack.

Andy
-- 
http://wingolog.org/



^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: when and unless
  2011-07-01  7:50   ` Andy Wingo
@ 2011-07-01 12:47     ` Ludovic Courtès
  0 siblings, 0 replies; 28+ messages in thread
From: Ludovic Courtès @ 2011-07-01 12:47 UTC (permalink / raw)
  To: Andy Wingo; +Cc: guile-devel

Andy Wingo <wingo@pobox.com> skribis:

> One place you might want to use them though is in type checks for Scheme
> code.  We currently don't do very much of that, but probably should in
> the future.  As in:
>
>   (define (parameter-fluid p)
>     (unless (parameter? p) (wrong-type-arg p 'parameter))
>     (struct-ref p 1))
>
> The advantage of `unless' over `if' is that the wrong-type-arg is not
> called in tail position, so the error message sees `parameter-fluid' on
> the stack.

Oh, interesting, good point!

Ludo’.



^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: when and unless
  2011-06-30 10:44 when and unless Andy Wingo
  2011-06-30 21:46 ` Ludovic Courtès
@ 2011-12-05 20:23 ` Andy Wingo
  2011-12-06  7:48   ` Marijn
  2011-12-06 14:39   ` Ludovic Courtès
  1 sibling, 2 replies; 28+ messages in thread
From: Andy Wingo @ 2011-12-05 20:23 UTC (permalink / raw)
  To: ludo; +Cc: guile-devel

Heya Ludo,

On Thu 30 Jun 2011 12:44, Andy Wingo <wingo@pobox.com> writes:

> I think we should add `when' and `unless' to the default environment.
>
> They go like this:
>
>   (define-syntax when
>     (syntax-rules ()
>       ((_ test then then* ...)
>        (if test (begin then then* ... (if #f #f))))))
>
>   (define-syntax unless
>     (syntax-rules ()
>       ((_ test else else* ...)
>        (if (not test) (begin else else* ... (if #f #f))))))

WDYT?  `unless' is nice for assertions, `when' is its converse, and most
Schemes have them.  I would like to add them to Guile too.

Andy
-- 
http://wingolog.org/



^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: when and unless
  2011-12-05 20:23 ` Andy Wingo
@ 2011-12-06  7:48   ` Marijn
  2011-12-06  8:29     ` Alex Shinn
  2011-12-06 19:05     ` Chris K. Jester-Young
  2011-12-06 14:39   ` Ludovic Courtès
  1 sibling, 2 replies; 28+ messages in thread
From: Marijn @ 2011-12-06  7:48 UTC (permalink / raw)
  To: Andy Wingo; +Cc: ludo, guile-devel

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hi Andy,

On 05-12-11 21:23, Andy Wingo wrote:
> Heya Ludo,
> 
> On Thu 30 Jun 2011 12:44, Andy Wingo <wingo@pobox.com> writes:
> 
>> I think we should add `when' and `unless' to the default
>> environment.
>> 
>> They go like this:
>> 
>> (define-syntax when (syntax-rules () ((_ test then then* ...) (if
>> test (begin then then* ... (if #f #f))))))
>> 
>> (define-syntax unless (syntax-rules () ((_ test else else* ...) 
>> (if (not test) (begin else else* ... (if #f #f))))))
> 
> WDYT?  `unless' is nice for assertions, `when' is its converse, and
> most Schemes have them.  I would like to add them to Guile too.

Couldn't help but wonder why they don't return the value of the last
body form, so I looked around a bit and both CLHS[1] and my racket
REPL seem to agree that they should:

$ racket
Welcome to Racket v5.2.0.4.
> (when #t 'hello)
'hello
> (unless #f 'hi)
'hi

Is there some other source that suggests that the return value should
be unspecified?

Marijn

[1]:http://clhs.lisp.se/Body/m_when_.htm
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.18 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iEYEARECAAYFAk7dyLEACgkQp/VmCx0OL2yAQACeL8y4js+HOZn1IBqFEJEl8n3I
i+MAn0TBdz2e1lP9n2EyP9PDlM7ATKUL
=nrWC
-----END PGP SIGNATURE-----



^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: when and unless
  2011-12-06  7:48   ` Marijn
@ 2011-12-06  8:29     ` Alex Shinn
  2011-12-06 11:17       ` David Kastrup
  2011-12-06 19:05     ` Chris K. Jester-Young
  1 sibling, 1 reply; 28+ messages in thread
From: Alex Shinn @ 2011-12-06  8:29 UTC (permalink / raw)
  To: Marijn; +Cc: Andy Wingo, ludo, guile-devel

On Tue, Dec 6, 2011 at 4:48 PM, Marijn <hkBst@gentoo.org> wrote:
>
> Couldn't help but wonder why they don't return the value of the last
> body form, so I looked around a bit and both CLHS[1] and my racket
> REPL seem to agree that they should:
>
> $ racket
> Welcome to Racket v5.2.0.4.
>> (when #t 'hello)
> 'hello
>> (unless #f 'hi)
> 'hi
>
> Is there some other source that suggests that the return value should
> be unspecified?

Because the result is meaningless when the condition is false.

CLHS returns nil in this case, but that fits with CL idioms and
not Scheme idioms.  when and unless are for side-effects - it's
better to write (and #t 'hello) if you want the result.

R7RS also leaves it unspecified.

-- 
Alex



^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: when and unless
  2011-12-06  8:29     ` Alex Shinn
@ 2011-12-06 11:17       ` David Kastrup
  2011-12-06 16:25         ` Andy Wingo
  2011-12-07 16:10         ` Chris K. Jester-Young
  0 siblings, 2 replies; 28+ messages in thread
From: David Kastrup @ 2011-12-06 11:17 UTC (permalink / raw)
  To: guile-devel

Alex Shinn <alexshinn@gmail.com> writes:

> On Tue, Dec 6, 2011 at 4:48 PM, Marijn <hkBst@gentoo.org> wrote:
>>
>> Couldn't help but wonder why they don't return the value of the last
>> body form, so I looked around a bit and both CLHS[1] and my racket
>> REPL seem to agree that they should:
>>
>> $ racket
>> Welcome to Racket v5.2.0.4.
>>> (when #t 'hello)
>> 'hello
>>> (unless #f 'hi)
>> 'hi
>>
>> Is there some other source that suggests that the return value should
>> be unspecified?
>
> Because the result is meaningless when the condition is false.
>
> CLHS returns nil in this case, but that fits with CL idioms and
> not Scheme idioms.  when and unless are for side-effects - it's
> better to write (and #t 'hello) if you want the result.
>
> R7RS also leaves it unspecified.

I've actually wondered if it would not make sense to return
*unspecified* in the case of the plain else-less if even if the
condition is true, namely when you write (if #t #t).

There is probably code relying on this to be #t, but frankly, this
appears like a recipe for breakage.

-- 
David Kastrup




^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: when and unless
  2011-12-05 20:23 ` Andy Wingo
  2011-12-06  7:48   ` Marijn
@ 2011-12-06 14:39   ` Ludovic Courtès
  2011-12-07 14:19     ` Ludovic Courtès
  1 sibling, 1 reply; 28+ messages in thread
From: Ludovic Courtès @ 2011-12-06 14:39 UTC (permalink / raw)
  To: Andy Wingo; +Cc: guile-devel

Hi,

Andy Wingo <wingo@pobox.com> skribis:

> On Thu 30 Jun 2011 12:44, Andy Wingo <wingo@pobox.com> writes:
>
>> I think we should add `when' and `unless' to the default environment.
>>
>> They go like this:
>>
>>   (define-syntax when
>>     (syntax-rules ()
>>       ((_ test then then* ...)
>>        (if test (begin then then* ... (if #f #f))))))
>>
>>   (define-syntax unless
>>     (syntax-rules ()
>>       ((_ test else else* ...)
>>        (if (not test) (begin else else* ... (if #f #f))))))
>
> WDYT?  `unless' is nice for assertions, `when' is its converse, and most
> Schemes have them.  I would like to add them to Guile too.

Yes, feel free.

Ludo’.



^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: when and unless
  2011-12-06 11:17       ` David Kastrup
@ 2011-12-06 16:25         ` Andy Wingo
  2011-12-06 16:42           ` David Kastrup
  2011-12-07 16:10         ` Chris K. Jester-Young
  1 sibling, 1 reply; 28+ messages in thread
From: Andy Wingo @ 2011-12-06 16:25 UTC (permalink / raw)
  To: David Kastrup; +Cc: guile-devel

On Tue 06 Dec 2011 12:17, David Kastrup <dak@gnu.org> writes:

> I've actually wondered if it would not make sense to return
> *unspecified* in the case of the plain else-less if even if the
> condition is true, namely when you write (if #t #t).

I have wondered this too.

> There is probably code relying on this to be #t, but frankly, this
> appears like a recipe for breakage.

Yeah.  A first (and probably worthwhile) step would be to warn if such a
statement is processed for value.  Warning on one-armed ifs in tail
position of a function would be harder, as you would have to analyze the
call sites of the function.

Regards,

Andy
-- 
http://wingolog.org/



^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: when and unless
  2011-12-06 16:25         ` Andy Wingo
@ 2011-12-06 16:42           ` David Kastrup
  2011-12-06 17:35             ` Andy Wingo
  0 siblings, 1 reply; 28+ messages in thread
From: David Kastrup @ 2011-12-06 16:42 UTC (permalink / raw)
  To: guile-devel

Andy Wingo <wingo@pobox.com> writes:

> On Tue 06 Dec 2011 12:17, David Kastrup <dak@gnu.org> writes:
>
>> I've actually wondered if it would not make sense to return
>> *unspecified* in the case of the plain else-less if even if the
>> condition is true, namely when you write (if #t #t).
>
> I have wondered this too.
>
>> There is probably code relying on this to be #t, but frankly, this
>> appears like a recipe for breakage.
>
> Yeah.  A first (and probably worthwhile) step would be to warn if such
> a statement is processed for value.

Well, is it being processed for value if what I do with the value is
calling unspecified? on it in order to find out whether I should warn
about a function returning a value when it shouldn't?

I am working on a language where returning values in certain contexts
might at one point of time might lead to the values being used.  So I
need to implement warnings to that effect in order to find out calls
_not_ returning *unspecified*...

-- 
David Kastrup




^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: when and unless
  2011-12-06 16:42           ` David Kastrup
@ 2011-12-06 17:35             ` Andy Wingo
  2011-12-06 22:08               ` David Kastrup
  0 siblings, 1 reply; 28+ messages in thread
From: Andy Wingo @ 2011-12-06 17:35 UTC (permalink / raw)
  To: David Kastrup; +Cc: guile-devel

On Tue 06 Dec 2011 17:42, David Kastrup <dak@gnu.org> writes:

> Andy Wingo <wingo@pobox.com> writes:
>
>> On Tue 06 Dec 2011 12:17, David Kastrup <dak@gnu.org> writes:
>>
>>> I've actually wondered if it would not make sense to return
>>> *unspecified* in the case of the plain else-less if even if the
>>> condition is true, namely when you write (if #t #t).
>>
>> A first (and probably worthwhile) step would be to warn if such
>> a statement is processed for value.
>
> Well, is it being processed for value if what I do with the value is
> calling unspecified? on it in order to find out whether I should warn
> about a function returning a value when it shouldn't?

Yes, it would be.

Note, in R5RS scheme, this should be true:

  (eqv? (if #f #f) (if #f #f))

In R6RS (and R7RS, I think) scheme it does not have any meaning --
implementations are free to do what they like.

The reason is that (if #f #f) returns "unspecified values" rather than a
canonical "unspecified value".  So the implementation may treat it like:

  (eqv? (values) (values))

which is strictly unspecified, as it is returning an unexpected number
of values to a continuation.

Guile 1.8:

    guile> (eqv? (values) (values))
    #f

Guile 2.0:

    scheme@(guile-user)> (eqv? (values) (values))
    ERROR: In procedure values:
    ERROR: Throw to key `vm-error' with args `(vm-run "Zero values returned to single-valued continuation" ())'.

Not a nicely printed error, but oh well.

Guile 2.0 returns a canonical unspecified value in this situation.  I
would like to consider returning 0 values instead in the future, but
figuring out how to do so without breaking the world is tricky.  It's
useful to hear about your experiences with *unspecified*.

> I am working on a language where returning values in certain contexts
> might at one point of time might lead to the values being used.  So I
> need to implement warnings to that effect in order to find out calls
> _not_ returning *unspecified*...

Have you considered using `(values)' as your way of saying, "I'm not
returning any values"?

Andy
-- 
http://wingolog.org/



^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: when and unless
  2011-12-06  7:48   ` Marijn
  2011-12-06  8:29     ` Alex Shinn
@ 2011-12-06 19:05     ` Chris K. Jester-Young
  2011-12-06 19:33       ` Andy Wingo
  1 sibling, 1 reply; 28+ messages in thread
From: Chris K. Jester-Young @ 2011-12-06 19:05 UTC (permalink / raw)
  To: guile-devel

On Tue, Dec 06, 2011 at 08:48:01AM +0100, Marijn wrote:
> Couldn't help but wonder why they don't return the value of the last
> body form, so I looked around a bit and both CLHS[1] and my racket
> REPL seem to agree that they should:
[...]
> Is there some other source that suggests that the return value should
> be unspecified?

This isn't so much because the return value is somehow specified or
useful, but rather to avoid breaking tail position. See this discussion
I had with Eli Barzilay where this is explained:

http://rotty.yi.org/irclogs/freenode/%23scheme/2011-11-02/#e208

(Start at the 07:24 timestamp if the fragment reference isn't working.)

Cheers,
Chris.



^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: when and unless
  2011-12-06 19:05     ` Chris K. Jester-Young
@ 2011-12-06 19:33       ` Andy Wingo
  0 siblings, 0 replies; 28+ messages in thread
From: Andy Wingo @ 2011-12-06 19:33 UTC (permalink / raw)
  To: guile-devel

On Tue 06 Dec 2011 20:05, "Chris K. Jester-Young" <cky944@gmail.com> writes:

> On Tue, Dec 06, 2011 at 08:48:01AM +0100, Marijn wrote:
>> Couldn't help but wonder why they don't return the value of the last
>> body form, so I looked around a bit and both CLHS[1] and my racket
>> REPL seem to agree that they should:
> [...]
>> Is there some other source that suggests that the return value should
>> be unspecified?
>
> This isn't so much because the return value is somehow specified or
> useful, but rather to avoid breaking tail position. See this discussion
> I had with Eli Barzilay where this is explained:
>
> http://rotty.yi.org/irclogs/freenode/%23scheme/2011-11-02/#e208
>
> (Start at the 07:24 timestamp if the fragment reference isn't working.)

Ah, OK.  Indeed this is a very good point, I didn't realize this
before.  Hummm.

Andy
-- 
http://wingolog.org/



^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: when and unless
  2011-12-06 17:35             ` Andy Wingo
@ 2011-12-06 22:08               ` David Kastrup
  2011-12-06 23:05                 ` Chris K. Jester-Young
  0 siblings, 1 reply; 28+ messages in thread
From: David Kastrup @ 2011-12-06 22:08 UTC (permalink / raw)
  To: Andy Wingo; +Cc: guile-devel

Andy Wingo <wingo@pobox.com> writes:

> which is strictly unspecified, as it is returning an unexpected number
> of values to a continuation.
>
> Guile 1.8:
>
>     guile> (eqv? (values) (values))
>     #f
>
> Guile 2.0:
>
>     scheme@(guile-user)> (eqv? (values) (values))
>     ERROR: In procedure values:
>     ERROR: Throw to key `vm-error' with args `(vm-run "Zero values returned to single-valued continuation" ())'.
>
> Not a nicely printed error, but oh well.
>
> Guile 2.0 returns a canonical unspecified value in this situation.  I
> would like to consider returning 0 values instead in the future, but
> figuring out how to do so without breaking the world is tricky.  It's
> useful to hear about your experiences with *unspecified*.
>
>> I am working on a language where returning values in certain contexts
>> might at one point of time might lead to the values being used.  So I
>> need to implement warnings to that effect in order to find out calls
>> _not_ returning *unspecified*...
>
> Have you considered using `(values)' as your way of saying, "I'm not
> returning any values"?

Testing for that is not all that much fun.  It is also rather useless
since pretty much all of the call-for-effect functions of Guile return
*unspecified* rather than (values).

It is not clear to me why (values) can't just evaluate to a single
*unspecified* just like '() evaluates to null.  Outside of
call-with-values, I don't see much need to treat it special.

-- 
David Kastrup



^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: when and unless
  2011-12-06 22:08               ` David Kastrup
@ 2011-12-06 23:05                 ` Chris K. Jester-Young
  2011-12-07  9:23                   ` David Kastrup
  0 siblings, 1 reply; 28+ messages in thread
From: Chris K. Jester-Young @ 2011-12-06 23:05 UTC (permalink / raw)
  To: guile-devel

On Tue, Dec 06, 2011 at 11:08:08PM +0100, David Kastrup wrote:
> > Have you considered using `(values)' as your way of saying, "I'm not
> > returning any values"?
> 
> Testing for that is not all that much fun.  It is also rather useless
> since pretty much all of the call-for-effect functions of Guile return
> *unspecified* rather than (values).

You're not really supposed to test for it. In fact, if you don't try to
use the value of when, unless, or one-armed ifs, you'll do just fine in
general.

> It is not clear to me why (values) can't just evaluate to a single
> *unspecified* just like '() evaluates to null.  Outside of
> call-with-values, I don't see much need to treat it special.

Implementing that would pretty much either require CPS transforms all
around (then you'd look at the arity of the continuation), or else
you'd have to be keeping track of the arity of the current continuation
some other way. Is it just me, or does that smell like Perl's wantarray?

Which brings me to a bigger question---do we even want anything like
wantarray? It seems so insanely hacky (to me), even in Perl code.

Just my humble opinion,
Chris.



^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: when and unless
  2011-12-06 23:05                 ` Chris K. Jester-Young
@ 2011-12-07  9:23                   ` David Kastrup
  2011-12-07 15:58                     ` Chris K. Jester-Young
  0 siblings, 1 reply; 28+ messages in thread
From: David Kastrup @ 2011-12-07  9:23 UTC (permalink / raw)
  To: guile-devel

"Chris K. Jester-Young" <cky944@gmail.com> writes:

> On Tue, Dec 06, 2011 at 11:08:08PM +0100, David Kastrup wrote:
>> > Have you considered using `(values)' as your way of saying, "I'm not
>> > returning any values"?
>> 
>> Testing for that is not all that much fun.  It is also rather useless
>> since pretty much all of the call-for-effect functions of Guile return
>> *unspecified* rather than (values).
>
> You're not really supposed to test for it.

Lilypond is not Scheme but has a more complex syntax.  You can use
Scheme in a lot of places with different implications on the grammar
depending on the type of the expression.  It would not be feasible to
create a separate Scheme calling operator for every possible type of
expression.  And "called just for action" is one such type.

>> It is not clear to me why (values) can't just evaluate to a single
>> *unspecified* just like '() evaluates to null.  Outside of
>> call-with-values, I don't see much need to treat it special.
>
> Implementing that would pretty much either require CPS transforms all
> around (then you'd look at the arity of the continuation), or else
> you'd have to be keeping track of the arity of the current
> continuation some other way. Is it just me, or does that smell like
> Perl's wantarray?

Well, you'd need to have

(call-with-values (lambda () *unspecified*) (lambda x (length x))) => 0

That's the actual clincher I presume?  If one takes a look at the Scheme
language definition, one finds for one thing:

(define (values . things)
  (call-with-current-continuation 
    (lambda (cont) (apply cont things))))

And, more importantly:

    Except for continuations created by the call-with-values procedure,
    all continuations take exactly one value.

That means that one _only_ needs to consider the implications on
call-with-values continuations.

And it is not like Guile has a problem distinguishing content and
package itself (at least Guile 1.8):

guile> (write *unspecified*)
#<unspecified>guile> (write (values))
#<values ()>guile> 

So I still don't quite see the problem that would arise from making
(eq? *unspecified* (values)) => #t

-- 
David Kastrup




^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: when and unless
  2011-12-06 14:39   ` Ludovic Courtès
@ 2011-12-07 14:19     ` Ludovic Courtès
  2011-12-07 14:27       ` David Kastrup
  2012-01-07  0:16       ` Andy Wingo
  0 siblings, 2 replies; 28+ messages in thread
From: Ludovic Courtès @ 2011-12-07 14:19 UTC (permalink / raw)
  To: guile-devel

Hi,

ludo@gnu.org (Ludovic Courtès) skribis:

> Andy Wingo <wingo@pobox.com> skribis:
>
>> On Thu 30 Jun 2011 12:44, Andy Wingo <wingo@pobox.com> writes:
>>
>>> I think we should add `when' and `unless' to the default environment.
>>>
>>> They go like this:
>>>
>>>   (define-syntax when
>>>     (syntax-rules ()
>>>       ((_ test then then* ...)
>>>        (if test (begin then then* ... (if #f #f))))))
>>>
>>>   (define-syntax unless
>>>     (syntax-rules ()
>>>       ((_ test else else* ...)
>>>        (if (not test) (begin else else* ... (if #f #f))))))
>>
>> WDYT?  `unless' is nice for assertions, `when' is its converse, and most
>> Schemes have them.  I would like to add them to Guile too.
>
> Yes, feel free.

Like Marijn, it seems more natural for me to return the values of the
body’s last expression, rather than *unspecified*.

Thanks,
Ludo’.




^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: when and unless
  2011-12-07 14:19     ` Ludovic Courtès
@ 2011-12-07 14:27       ` David Kastrup
  2012-01-07  0:16       ` Andy Wingo
  1 sibling, 0 replies; 28+ messages in thread
From: David Kastrup @ 2011-12-07 14:27 UTC (permalink / raw)
  To: guile-devel

ludo@gnu.org (Ludovic Courtès) writes:

> ludo@gnu.org (Ludovic Courtès) skribis:
>
>> Andy Wingo <wingo@pobox.com> skribis:
>>
>>> On Thu 30 Jun 2011 12:44, Andy Wingo <wingo@pobox.com> writes:
>>>
>>>> I think we should add `when' and `unless' to the default environment.
>>>>
>>>> They go like this:
>>>>
>>>>   (define-syntax when
>>>>     (syntax-rules ()
>>>>       ((_ test then then* ...)
>>>>        (if test (begin then then* ... (if #f #f))))))
>>>>
>>>>   (define-syntax unless
>>>>     (syntax-rules ()
>>>>       ((_ test else else* ...)
>>>>        (if (not test) (begin else else* ... (if #f #f))))))
>>>
>>> WDYT?  `unless' is nice for assertions, `when' is its converse, and most
>>> Schemes have them.  I would like to add them to Guile too.
>>
>> Yes, feel free.
>
> Like Marijn, it seems more natural for me to return the values of the
> body’s last expression, rather than *unspecified*.

Can you explain how that would even make sense?  You can't return a
specified value when the condition is not true since then no form gets
evaluated.  So where is the point in returning a value that is only
sometimes specified?  "Sometimes specified" logically is pretty much the
same as "unspecified", and then we might return *unspecified* right
away.

-- 
David Kastrup




^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: when and unless
  2011-12-07  9:23                   ` David Kastrup
@ 2011-12-07 15:58                     ` Chris K. Jester-Young
  2011-12-08  8:42                       ` David Kastrup
  0 siblings, 1 reply; 28+ messages in thread
From: Chris K. Jester-Young @ 2011-12-07 15:58 UTC (permalink / raw)
  To: guile-devel

On Wed, Dec 07, 2011 at 10:23:25AM +0100, David Kastrup wrote:
> Lilypond is not Scheme but has a more complex syntax.  You can use
> Scheme in a lot of places with different implications on the grammar
> depending on the type of the expression.  It would not be feasible to
> create a separate Scheme calling operator for every possible type of
> expression.  And "called just for action" is one such type.

In that case, to be proper, you have to do what the REPL does, which is
to wrap the Scheme expression within a call-with-values wherever you
process the calling operator. Remember that the continuation can be a
case-lambda:

    (call-with-values
     (lambda () (values))
     (case-lambda
      (() "No return values")
      ((x) (format #f "Single value: ~a" x))
      (x (format #f "Multiple values: ~a" x))))

(Guile 2.0 has built-in (VM-level) support for case-lambda, which makes
this super awesome.)

> Well, you'd need to have
> 
> (call-with-values (lambda () *unspecified*) (lambda x (length x))) => 0
[...]
> That means that one _only_ needs to consider the implications on
> call-with-values continuations.

Correct. However, how would you detect whether you're in a context where
call-with-values is being used? Here are some things that won't work:

1. You can't walk the stack. Your void expression would be in tail
   position (it would transfer to the continuation directly, not return
   to call-with-values---try (call-with-values (lambda () (throw 'foo))
   (lambda () 42)) and see what the backtrace looks like).

2. Guile's continuations don't provide meaningful arities: (call/cc
   (lambda (k) (procedure-minimum-arity k))) always says it takes zero
   or more arguments. (Same deal applies with Racket, so I presume it's
   not "just a Guile quirk".)

> And it is not like Guile has a problem distinguishing content and
> package itself (at least Guile 1.8):
> 
> guile> (write *unspecified*)
> #<unspecified>guile> (write (values))
> #<values ()>guile> 

In Guile 2.0, multiple values is not a first-class object. Instead, it
works like Common Lisp: in any context where a single value is needed,
and multiple values are supplied, then only the first value is used,
and the rest are thrown away.

    scheme@(guile-user)> (+ (values 1 2 3) (values 4 5 6))
    $1 = 5
    scheme@(guile-user)> (+ (values 1 2 3) (values))
    ERROR: In procedure values:
    ERROR: Throw to key `vm-error' with args `(vm-run "Zero values returned to single-valued continuation" ())'.

> So I still don't quite see the problem that would arise from making
> (eq? *unspecified* (values)) => #t

Simply that (values) is not valid to pass to eq?, since eq? is a normal
function, that thus expects one value for every argument. That this may
possibly work for Guile 1.8 is simply an accident of its implementation
of multiple values.

Cheers,
Chris.



^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: when and unless
  2011-12-06 11:17       ` David Kastrup
  2011-12-06 16:25         ` Andy Wingo
@ 2011-12-07 16:10         ` Chris K. Jester-Young
  1 sibling, 0 replies; 28+ messages in thread
From: Chris K. Jester-Young @ 2011-12-07 16:10 UTC (permalink / raw)
  To: guile-devel

On Tue, Dec 06, 2011 at 12:17:06PM +0100, David Kastrup wrote:
> I've actually wondered if it would not make sense to return
> *unspecified* in the case of the plain else-less if even if the
> condition is true, namely when you write (if #t #t).

This cannot be done without breaking the tail position guarantee that
"if" has. i.e., Scheme specifies that for expressions of the form

    (if TEST THEN ELSE)
    (if TEST THEN)

that THEN and ELSE are both in tail position. Tail position means that
the evaluation of THEN or ELSE returns to the caller directly, and
there is no chance for the system to intervene, such as by replacing
the return value with unspecified.

Cheers,
Chris.



^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: when and unless
  2011-12-07 15:58                     ` Chris K. Jester-Young
@ 2011-12-08  8:42                       ` David Kastrup
  2011-12-08 15:34                         ` Chris K. Jester-Young
  2011-12-08 18:10                         ` Ian Price
  0 siblings, 2 replies; 28+ messages in thread
From: David Kastrup @ 2011-12-08  8:42 UTC (permalink / raw)
  To: guile-devel

"Chris K. Jester-Young" <cky944@gmail.com> writes:

> On Wed, Dec 07, 2011 at 10:23:25AM +0100, David Kastrup wrote:
>
>> Well, you'd need to have
>> 
>> (call-with-values (lambda () *unspecified*) (lambda x (length x))) => 0
> [...]
>> That means that one _only_ needs to consider the implications on
>> call-with-values continuations.
>
> Correct. However, how would you detect whether you're in a context where
> call-with-values is being used? Here are some things that won't work:
>
> 1. You can't walk the stack. Your void expression would be in tail
>    position (it would transfer to the continuation directly, not return
>    to call-with-values---try (call-with-values (lambda () (throw 'foo))
>    (lambda () 42)) and see what the backtrace looks like).
>
> 2. Guile's continuations don't provide meaningful arities: (call/cc
>    (lambda (k) (procedure-minimum-arity k))) always says it takes zero
>    or more arguments. (Same deal applies with Racket, so I presume it's
>    not "just a Guile quirk".)

> In Guile 2.0, multiple values is not a first-class object. Instead, it
> works like Common Lisp: in any context where a single value is needed,
> and multiple values are supplied, then only the first value is used,
> and the rest are thrown away.

>     scheme@(guile-user)> (+ (values 1 2 3) (values 4 5 6))
>     $1 = 5
>     scheme@(guile-user)> (+ (values 1 2 3) (values))
>     ERROR: In procedure values:
>     ERROR: Throw to key `vm-error' with args `(vm-run "Zero values
> returned to single-valued continuation" ())'.
>
>> So I still don't quite see the problem that would arise from making
>> (eq? *unspecified* (values)) => #t
>
> Simply that (values) is not valid to pass to eq?, since eq? is a normal
> function, that thus expects one value for every argument. That this may
> possibly work for Guile 1.8 is simply an accident of its implementation
> of multiple values.

In any way, you have the existing C API which returns single values for
things like scm_eval.

So here is another proposal: (values) is not the same as *unspecified*.
But if you take the first value of a values list in single-value
contexts, there is nothing about that coercion mechanism that would keep
you from using *unspecified* whenever that values list would be empty.

So you would have

(length (call-with-values (lambda () *unspecified*) list)) => 1
(length (call-with-values (lambda () (values)) list)) => 0
(eq? (values) *unspecified*) => #t

After all, you will also have

(length (call-with-values (lambda () (values #t #t)) list)) => 2
(length (call-with-values (lambda () #t) list)) => 1
(eq? (values #t #t) #t) => #t

and nobody seems all too worried about that, I guess.  There will often
be call chaining through C.  You can't throw an error every time
somebody calls a C function like scm_eval or scm_apply or scm_call for
effect and complain whenever the called function exits with the
equivalent of (values), and you can't remove all of the C API at once
and replace it with something that glues together continuations in a
multiple-value passing manner.

-- 
David Kastrup




^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: when and unless
  2011-12-08  8:42                       ` David Kastrup
@ 2011-12-08 15:34                         ` Chris K. Jester-Young
  2011-12-08 16:10                           ` David Kastrup
  2011-12-08 18:10                         ` Ian Price
  1 sibling, 1 reply; 28+ messages in thread
From: Chris K. Jester-Young @ 2011-12-08 15:34 UTC (permalink / raw)
  To: guile-devel

On Thu, Dec 08, 2011 at 09:42:36AM +0100, David Kastrup wrote:
> So here is another proposal: (values) is not the same as *unspecified*.
> But if you take the first value of a values list in single-value
> contexts, there is nothing about that coercion mechanism that would keep
> you from using *unspecified* whenever that values list would be empty.

That's easy to implement (patch at bottom of post; I tested it). The
question for the people on the list to decide is whether it's a good
idea. :-) Personally, I don't object to it, but, perhaps others do.

Cheers,
Chris.

			*	*	*

diff --git a/libguile/vm-i-system.c b/libguile/vm-i-system.c
index 474fe78..6ce5ee3 100644
--- a/libguile/vm-i-system.c
+++ b/libguile/vm-i-system.c
@@ -1311,7 +1311,7 @@ VM_DEFINE_INSTRUCTION (68, return_values, "return/values", 1, -1, -1)
       /* Finally null the end of the stack */
       NULLSTACK (vals + nvalues - sp);
     }
-  else if (nvalues >= 1)
+  else
     {
       /* Multiple values for a single-valued continuation -- here's where I
          break with guile tradition and try and do something sensible. (Also,
@@ -1324,13 +1324,11 @@ VM_DEFINE_INSTRUCTION (68, return_values, "return/values", 1, -1, -1)
       fp = SCM_FRAME_DYNAMIC_LINK (fp);
         
       /* Push first value */
-      *++sp = vals[1];
+      *++sp = nvalues >= 1 ? vals[1] : SCM_UNSPECIFIED;
              
       /* Finally null the end of the stack */
       NULLSTACK (vals + nvalues - sp);
     }
-  else
-    goto vm_error_no_values;
 
   /* Restore the last program */
   program = SCM_FRAME_PROGRAM (fp);



^ permalink raw reply related	[flat|nested] 28+ messages in thread

* Re: when and unless
  2011-12-08 15:34                         ` Chris K. Jester-Young
@ 2011-12-08 16:10                           ` David Kastrup
  0 siblings, 0 replies; 28+ messages in thread
From: David Kastrup @ 2011-12-08 16:10 UTC (permalink / raw)
  To: guile-devel

"Chris K. Jester-Young" <cky944@gmail.com> writes:

> On Thu, Dec 08, 2011 at 09:42:36AM +0100, David Kastrup wrote:
>> So here is another proposal: (values) is not the same as *unspecified*.
>> But if you take the first value of a values list in single-value
>> contexts, there is nothing about that coercion mechanism that would keep
>> you from using *unspecified* whenever that values list would be empty.
>
> That's easy to implement (patch at bottom of post; I tested it). The
> question for the people on the list to decide is whether it's a good
> idea. :-) Personally, I don't object to it, but, perhaps others do.

Well, the bad thing about it is that using *unspecified* explicitly is
not equivalent to what Guile does (presuming that it uses (values)
whenever it does not return a value) even though it counts as eq?, just
like using (values #t #t) is not equivalent to what #t does, but will
still count as eq?.

It is somewhat similar to how Lua deals with nil (which is a mixture of
SCM_UNSPECIFIED and SCM_UNDEFINED in semantics) and tail call argument
lists and multiple/single/no value returns.  You can figure out the
difference between a nil return value and none, but not without
tail-calling another function in which you explicitly ask for the number
of arguments.

Anyway, in Guile there are wagonloads of C functions that return exactly
1 value.  I don't think you can always just let them blow up when they
don't have a value to deliver.  That would be a major migration pain.

If you want to discourage people at one time from confusing the two, let
the REPL print *unspecified* when that (rather than no value at all) is
returned.  But I don't think that you should start with this too early.
I suppose user-defined C functions, instead of returning
SCM_UNSPECIFIED, would have to call something like scm_return_values
(SCM_UNDEFINED); instead.

-- 
David Kastrup




^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: when and unless
  2011-12-08  8:42                       ` David Kastrup
  2011-12-08 15:34                         ` Chris K. Jester-Young
@ 2011-12-08 18:10                         ` Ian Price
  1 sibling, 0 replies; 28+ messages in thread
From: Ian Price @ 2011-12-08 18:10 UTC (permalink / raw)
  To: David Kastrup; +Cc: guile-devel

David Kastrup <dak@gnu.org> writes:

> So here is another proposal: (values) is not the same as *unspecified*.
> But if you take the first value of a values list in single-value
> contexts, there is nothing about that coercion mechanism that would keep
> you from using *unspecified* whenever that values list would be empty.
This seems like a special case of the, I think, CL behaviour where you
get a nil for each of the values expected that were not explicitly
returned. Not my preference, but certainly not the worst thing you can
do.

(As an aside, people who want this behaviour can use
https://gist.github.com/1359350 which I wrote for dsmith a while back)

> So you would have
>
> (length (call-with-values (lambda () *unspecified*) list)) => 1
> (length (call-with-values (lambda () (values)) list)) => 0
> (eq? (values) *unspecified*) => #t
>
> After all, you will also have
>
> (length (call-with-values (lambda () (values #t #t)) list)) => 2
> (length (call-with-values (lambda () #t) list)) => 1
> (eq? (values #t #t) #t) => #t
>
> and nobody seems all too worried about that, I guess.
Some of us are, I think in the guile community this is a minority
view.

-- 
Ian Price

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



^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: when and unless
  2011-12-07 14:19     ` Ludovic Courtès
  2011-12-07 14:27       ` David Kastrup
@ 2012-01-07  0:16       ` Andy Wingo
  2012-01-07 22:36         ` Ludovic Courtès
  1 sibling, 1 reply; 28+ messages in thread
From: Andy Wingo @ 2012-01-07  0:16 UTC (permalink / raw)
  To: Ludovic Courtès; +Cc: guile-devel

Hi,

On Wed 07 Dec 2011 15:19, ludo@gnu.org (Ludovic Courtès) writes:

>>> On Thu 30 Jun 2011 12:44, Andy Wingo <wingo@pobox.com> writes:
>>>
>>>> I think we should add `when' and `unless' to the default environment.
>
> Like Marijn, it seems more natural for me to return the values of the
> body’s last expression, rather than *unspecified*.

Given that there are reasonable cases for `when' and `unless' in
side-effecting loops, it is indeed probably best to preserve the
<tail sequence> nature of the body of these forms.

Are you OK with adding them like this:

 (define-syntax (when condition stmt stmt* ...)
   (if condition (begin stmt stmt* ...)))

 (define-syntax (unless condition stmt stmt* ...)
   (if (not condition) (begin stmt stmt* ...)))

Andy
-- 
http://wingolog.org/



^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: when and unless
  2012-01-07  0:16       ` Andy Wingo
@ 2012-01-07 22:36         ` Ludovic Courtès
  2012-01-20 20:19           ` Andy Wingo
  0 siblings, 1 reply; 28+ messages in thread
From: Ludovic Courtès @ 2012-01-07 22:36 UTC (permalink / raw)
  To: guile-devel

Hi!

Andy Wingo <wingo@pobox.com> skribis:

> Are you OK with adding them like this:
>
>  (define-syntax (when condition stmt stmt* ...)
>    (if condition (begin stmt stmt* ...)))
>
>  (define-syntax (unless condition stmt stmt* ...)
>    (if (not condition) (begin stmt stmt* ...)))

Yes!

(‘define-syntax-rule’ I suppose?)

Ludo’.




^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: when and unless
  2012-01-07 22:36         ` Ludovic Courtès
@ 2012-01-20 20:19           ` Andy Wingo
  0 siblings, 0 replies; 28+ messages in thread
From: Andy Wingo @ 2012-01-20 20:19 UTC (permalink / raw)
  To: Ludovic Courtès; +Cc: guile-devel

Heya,

On Sat 07 Jan 2012 23:36, ludo@gnu.org (Ludovic Courtès) writes:

> Andy Wingo <wingo@pobox.com> skribis:
>
>>  (define-syntax (when condition stmt stmt* ...)
>>    (if condition (begin stmt stmt* ...)))
>>
>>  (define-syntax (unless condition stmt stmt* ...)
>>    (if (not condition) (begin stmt stmt* ...)))
>
> Yes!
>
> (‘define-syntax-rule’ I suppose?)

Pushed!

Cheers,

Andy
-- 
http://wingolog.org/



^ permalink raw reply	[flat|nested] 28+ messages in thread

end of thread, other threads:[~2012-01-20 20:19 UTC | newest]

Thread overview: 28+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-06-30 10:44 when and unless Andy Wingo
2011-06-30 21:46 ` Ludovic Courtès
2011-07-01  7:50   ` Andy Wingo
2011-07-01 12:47     ` Ludovic Courtès
2011-12-05 20:23 ` Andy Wingo
2011-12-06  7:48   ` Marijn
2011-12-06  8:29     ` Alex Shinn
2011-12-06 11:17       ` David Kastrup
2011-12-06 16:25         ` Andy Wingo
2011-12-06 16:42           ` David Kastrup
2011-12-06 17:35             ` Andy Wingo
2011-12-06 22:08               ` David Kastrup
2011-12-06 23:05                 ` Chris K. Jester-Young
2011-12-07  9:23                   ` David Kastrup
2011-12-07 15:58                     ` Chris K. Jester-Young
2011-12-08  8:42                       ` David Kastrup
2011-12-08 15:34                         ` Chris K. Jester-Young
2011-12-08 16:10                           ` David Kastrup
2011-12-08 18:10                         ` Ian Price
2011-12-07 16:10         ` Chris K. Jester-Young
2011-12-06 19:05     ` Chris K. Jester-Young
2011-12-06 19:33       ` Andy Wingo
2011-12-06 14:39   ` Ludovic Courtès
2011-12-07 14:19     ` Ludovic Courtès
2011-12-07 14:27       ` David Kastrup
2012-01-07  0:16       ` Andy Wingo
2012-01-07 22:36         ` Ludovic Courtès
2012-01-20 20:19           ` Andy Wingo

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).