unofficial mirror of guile-user@gnu.org 
 help / color / mirror / Atom feed
* question about values
@ 2020-03-17 23:50 Massimiliano Gubinelli
  2020-03-18  6:12 ` Taylan Kammer
  0 siblings, 1 reply; 11+ messages in thread
From: Massimiliano Gubinelli @ 2020-03-17 23:50 UTC (permalink / raw)
  To: guile-user

Hi all,

 I do not understand what happens here:

mgubi@Ulrike guile3-usr % guile
guile> (version)
"1.8.8"
guile> (call-with-values (lambda () (let ((a (values "a" "b" "c"))) a)) (lambda body body))
("a" "b" "c")


mgubi@Ulrike guile3-usr % bin/guile
GNU Guile 3.0.1
Copyright (C) 1995-2020 Free Software Foundation, Inc.

Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'.
This program is free software, and you are welcome to redistribute it
under certain conditions; type `,show c' for details.

Enter `,help' for help.
scheme@(guile-user)> (version)
$1 = "3.0.1"
scheme@(guile-user)> (call-with-values (lambda () (let ((a (values "a" "b" "c"))) a)) (lambda body body))
$2 = ("a")


Why the two versions of Guile behave differently? Which is the "correct" behaviour, and in case: how to propagate multiple results safely?

Thanks!

Massimiliano




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

* Re: question about values
  2020-03-17 23:50 question about values Massimiliano Gubinelli
@ 2020-03-18  6:12 ` Taylan Kammer
  2020-03-18  9:55   ` Massimiliano Gubinelli
  0 siblings, 1 reply; 11+ messages in thread
From: Taylan Kammer @ 2020-03-18  6:12 UTC (permalink / raw)
  To: Massimiliano Gubinelli, guile-user

On 18.03.2020 00:50, Massimiliano Gubinelli wrote:
> (let ((a (values "a" "b" "c"))) a)

The result of (values x y z) is not a kind of object that contains three 
values (like a list or vector).  It's three separate values that would 
need to be put into three separate variables.  But you're only naming 
one variable (a).  So strictly speaking the code is "wrong".

In Guile 1.8, multiple values were actually put into some special kind 
of object (which was not very efficient) so code like that still somehow 
worked even thought it's technically wrong.

Starting from Guile 2.0, providing multiple values in a context where 
only one is expected causes the extra values to be ignored.


Happy to answer further questions about this.  Multiple-values can be a 
tricky concept to grasp because most other programming languages don't 
have it.

- Taylan



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

* Re: question about values
  2020-03-18  6:12 ` Taylan Kammer
@ 2020-03-18  9:55   ` Massimiliano Gubinelli
  2020-03-18 11:06     ` Massimiliano Gubinelli
  2020-03-18 12:39     ` Matt Wette
  0 siblings, 2 replies; 11+ messages in thread
From: Massimiliano Gubinelli @ 2020-03-18  9:55 UTC (permalink / raw)
  To: Taylan Kammer; +Cc: guile-user

Thanks Taylan,

> On 18. Mar 2020, at 07:12, Taylan Kammer <taylan.kammer@gmail.com> wrote:
> 
> On 18.03.2020 00:50, Massimiliano Gubinelli wrote:
>> (let ((a (values "a" "b" "c"))) a)
> 
> The result of (values x y z) is not a kind of object that contains three values (like a list or vector).  It's three separate values that would need to be put into three separate variables.  But you're only naming one variable (a).  So strictly speaking the code is "wrong".
> 
> In Guile 1.8, multiple values were actually put into some special kind of object (which was not very efficient) so code like that still somehow worked even thought it's technically wrong.
> 
> Starting from Guile 2.0, providing multiple values in a context where only one is expected causes the extra values to be ignored.
> 
> 

I understand the point but then it comes to the problem how to handle this in macros. For example if bar is a proceduce which returns multiple values and I have a macro "my-macro" which wraps the call with some initialization and finalization code and I write

(my-macro (bar))

how to write this macro without knowing if bar is returning multiple values or not? For example I would like the code above to expand into

(begin
 (initialization-code)
 (let ((ret (bar))) 
  (finalization-code) 
  ret))


But this does not work as shown by the example above. How to implement this macro correctly?

best
Max


> Happy to answer further questions about this.  Multiple-values can be a tricky concept to grasp because most other programming languages don't have it.
> 
> - Taylan




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

* Re: question about values
  2020-03-18  9:55   ` Massimiliano Gubinelli
@ 2020-03-18 11:06     ` Massimiliano Gubinelli
  2020-03-18 12:39     ` Matt Wette
  1 sibling, 0 replies; 11+ messages in thread
From: Massimiliano Gubinelli @ 2020-03-18 11:06 UTC (permalink / raw)
  To: Taylan Kammer; +Cc: guile-user

Let me precise my concerns.

I know I can do 

(begin
 (initialization-code)
 (let ((vals (call-with-values (lambda () (bar)) (lambda vals vals))))
  (finalization)
  (apply values vals)))

this is the hack I'm using now in my code. But my question is: does it incur performance penalties (it will be a macro, so used also in many other context where bar returns only a single value)

Is there no better way to have multiple values interact in a composable way with macros???

Max


> On 18. Mar 2020, at 10:55, Massimiliano Gubinelli <m.gubinelli@gmail.com> wrote:
> 
> Thanks Taylan,
> 
>> On 18. Mar 2020, at 07:12, Taylan Kammer <taylan.kammer@gmail.com> wrote:
>> 
>> On 18.03.2020 00:50, Massimiliano Gubinelli wrote:
>>> (let ((a (values "a" "b" "c"))) a)
>> 
>> The result of (values x y z) is not a kind of object that contains three values (like a list or vector).  It's three separate values that would need to be put into three separate variables.  But you're only naming one variable (a).  So strictly speaking the code is "wrong".
>> 
>> In Guile 1.8, multiple values were actually put into some special kind of object (which was not very efficient) so code like that still somehow worked even thought it's technically wrong.
>> 
>> Starting from Guile 2.0, providing multiple values in a context where only one is expected causes the extra values to be ignored.
>> 
>> 
> 
> I understand the point but then it comes to the problem how to handle this in macros. For example if bar is a proceduce which returns multiple values and I have a macro "my-macro" which wraps the call with some initialization and finalization code and I write
> 
> (my-macro (bar))
> 
> how to write this macro without knowing if bar is returning multiple values or not? For example I would like the code above to expand into
> 
> (begin
> (initialization-code)
> (let ((ret (bar))) 
>  (finalization-code) 
>  ret))
> 
> 
> But this does not work as shown by the example above. How to implement this macro correctly?
> 
> best
> Max
> 
> 
>> Happy to answer further questions about this.  Multiple-values can be a tricky concept to grasp because most other programming languages don't have it.
>> 
>> - Taylan



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

* Re: question about values
  2020-03-18  9:55   ` Massimiliano Gubinelli
  2020-03-18 11:06     ` Massimiliano Gubinelli
@ 2020-03-18 12:39     ` Matt Wette
  2020-03-18 13:11       ` Massimiliano Gubinelli
  1 sibling, 1 reply; 11+ messages in thread
From: Matt Wette @ 2020-03-18 12:39 UTC (permalink / raw)
  To: guile-user



On 3/18/20 2:55 AM, Massimiliano Gubinelli wrote:
> I understand the point but then it comes to the problem how to handle this in macros. For example if bar is a proceduce which returns multiple values and I have a macro "my-macro" which wraps the call with some initialization and finalization code and I write
>
> (my-macro (bar))
>
> how to write this macro without knowing if bar is returning multiple values or not? For example I would like the code above to expand into
>
> (begin
>   (initialization-code)
>   (let ((ret (bar)))
>    (finalization-code)
>    ret))
>
>
> But this does not work as shown by the example above. How to implement this macro correctly?
>
>

How about calling (my-macro/values bar) where my-macro/values expands to

(call-with-values (lambda () (bar))
   (lambda args (finalization-code) (apply values args))

Matt




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

* Re: question about values
  2020-03-18 12:39     ` Matt Wette
@ 2020-03-18 13:11       ` Massimiliano Gubinelli
  2020-03-18 14:06         ` John Cowan
  0 siblings, 1 reply; 11+ messages in thread
From: Massimiliano Gubinelli @ 2020-03-18 13:11 UTC (permalink / raw)
  To: Matt Wette; +Cc: guile-user


> On 18. Mar 2020, at 13:39, Matt Wette <matt.wette@gmail.com> wrote:
> 
> 
> How about calling (my-macro/values bar) where my-macro/values expands to
> 
> (call-with-values (lambda () (bar))
>   (lambda args (finalization-code) (apply values args))
> 
> Matt
> 
> 

Yeah! I like this better. But still wraps and unwraps the result.

 Is there any performance penalty in that? 

Apart from my specific user case I wonder how and why in general multiple values are used. Seems they are not well integrated in the current Guile implementation. In my naive opinion the behaviour of Guile 1.8 was more consistent.

Max





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

* Re: question about values
  2020-03-18 13:11       ` Massimiliano Gubinelli
@ 2020-03-18 14:06         ` John Cowan
  2020-03-18 14:40           ` Massimiliano Gubinelli
  0 siblings, 1 reply; 11+ messages in thread
From: John Cowan @ 2020-03-18 14:06 UTC (permalink / raw)
  To: Massimiliano Gubinelli; +Cc: guile-user, Matt Wette

There is going to be a performance penalty, because you are taking multiple
values (which is not a value) and making it into a value by creating a
list.  There is no getting away from that except to exclude multiple values.

Note also that if the procedure throws an exception, your finalizer will
never be run.  Consider using dynamic-wind, whose whole purpose is to make
sure that an initializer and a finalizer are always run.

On Wed, Mar 18, 2020 at 9:11 AM Massimiliano Gubinelli <
m.gubinelli@gmail.com> wrote:

>
> > On 18. Mar 2020, at 13:39, Matt Wette <matt.wette@gmail.com> wrote:
> >
> >
> > How about calling (my-macro/values bar) where my-macro/values expands to
> >
> > (call-with-values (lambda () (bar))
> >   (lambda args (finalization-code) (apply values args))
> >
> > Matt
> >
> >
>
> Yeah! I like this better. But still wraps and unwraps the result.
>
>  Is there any performance penalty in that?
>
> Apart from my specific user case I wonder how and why in general multiple
> values are used. Seems they are not well integrated in the current Guile
> implementation. In my naive opinion the behaviour of Guile 1.8 was more
> consistent.
>
> Max
>
>
>
>


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

* Re: question about values
  2020-03-18 14:06         ` John Cowan
@ 2020-03-18 14:40           ` Massimiliano Gubinelli
  2020-03-18 14:48             ` Massimiliano Gubinelli
  0 siblings, 1 reply; 11+ messages in thread
From: Massimiliano Gubinelli @ 2020-03-18 14:40 UTC (permalink / raw)
  To: John Cowan; +Cc: guile-user, Matt Wette

Good point with dynamic-wind. Does it pass along also multiple values or has the same problem?

m


> On 18. Mar 2020, at 15:06, John Cowan <cowan@ccil.org> wrote:
> 
> There is going to be a performance penalty, because you are taking multiple values (which is not a value) and making it into a value by creating a list.  There is no getting away from that except to exclude multiple values.
> 
> Note also that if the procedure throws an exception, your finalizer will never be run.  Consider using dynamic-wind, whose whole purpose is to make sure that an initializer and a finalizer are always run.
> 
> On Wed, Mar 18, 2020 at 9:11 AM Massimiliano Gubinelli <m.gubinelli@gmail.com <mailto:m.gubinelli@gmail.com>> wrote:
> 
> > On 18. Mar 2020, at 13:39, Matt Wette <matt.wette@gmail.com <mailto:matt.wette@gmail.com>> wrote:
> > 
> > 
> > How about calling (my-macro/values bar) where my-macro/values expands to
> > 
> > (call-with-values (lambda () (bar))
> >   (lambda args (finalization-code) (apply values args))
> > 
> > Matt
> > 
> > 
> 
> Yeah! I like this better. But still wraps and unwraps the result.
> 
>  Is there any performance penalty in that? 
> 
> Apart from my specific user case I wonder how and why in general multiple values are used. Seems they are not well integrated in the current Guile implementation. In my naive opinion the behaviour of Guile 1.8 was more consistent.
> 
> Max
> 
> 
> 



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

* Re: question about values
  2020-03-18 14:40           ` Massimiliano Gubinelli
@ 2020-03-18 14:48             ` Massimiliano Gubinelli
  2020-03-18 15:08               ` tomas
  0 siblings, 1 reply; 11+ messages in thread
From: Massimiliano Gubinelli @ 2020-03-18 14:48 UTC (permalink / raw)
  To: John Cowan; +Cc: guile-user, Matt Wette


> On 18. Mar 2020, at 15:40, Massimiliano Gubinelli <m.gubinelli@gmail.com> wrote:
> 
> Good point with dynamic-wind. Does it pass along also multiple values or has the same problem?
> 

Does not work...

mgubi@Ulrike guile3-usr % bin/guile
GNU Guile 3.0.1
Copyright (C) 1995-2020 Free Software Foundation, Inc.

Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'.
This program is free software, and you are welcome to redistribute it
under certain conditions; type `,show c' for details.

Enter `,help' for help.
scheme@(guile-user)> (call-with-values (lambda ()
 (dynamic-wind (lambda () (display "initialize\n"))
  (lambda () (let ((a (values "a" "b" "c"))) a))
  (lambda () (display "finalize\n"))))
  (lambda body body))
initialize
finalize
$1 = ("a")
scheme@(guile-user)> 

Isn't this a bug??? In my view it breaks composability of scheme code.

Best,
Max



> m
> 
> 
>> On 18. Mar 2020, at 15:06, John Cowan <cowan@ccil.org> wrote:
>> 
>> There is going to be a performance penalty, because you are taking multiple values (which is not a value) and making it into a value by creating a list.  There is no getting away from that except to exclude multiple values.
>> 
>> Note also that if the procedure throws an exception, your finalizer will never be run.  Consider using dynamic-wind, whose whole purpose is to make sure that an initializer and a finalizer are always run.
>> 
>> On Wed, Mar 18, 2020 at 9:11 AM Massimiliano Gubinelli <m.gubinelli@gmail.com> wrote:
>> 
>> > On 18. Mar 2020, at 13:39, Matt Wette <matt.wette@gmail.com> wrote:
>> > 
>> > 
>> > How about calling (my-macro/values bar) where my-macro/values expands to
>> > 
>> > (call-with-values (lambda () (bar))
>> >   (lambda args (finalization-code) (apply values args))
>> > 
>> > Matt
>> > 
>> > 
>> 
>> Yeah! I like this better. But still wraps and unwraps the result.
>> 
>>  Is there any performance penalty in that? 
>> 
>> Apart from my specific user case I wonder how and why in general multiple values are used. Seems they are not well integrated in the current Guile implementation. In my naive opinion the behaviour of Guile 1.8 was more consistent.
>> 
>> Max
>> 
>> 
>> 
> 




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

* Re: question about values
  2020-03-18 14:48             ` Massimiliano Gubinelli
@ 2020-03-18 15:08               ` tomas
  2020-03-18 15:34                 ` Massimiliano Gubinelli
  0 siblings, 1 reply; 11+ messages in thread
From: tomas @ 2020-03-18 15:08 UTC (permalink / raw)
  To: Massimiliano Gubinelli; +Cc: guile-user, Matt Wette

[-- Attachment #1: Type: text/plain, Size: 1335 bytes --]

On Wed, Mar 18, 2020 at 03:48:03PM +0100, Massimiliano Gubinelli wrote:
> 
> > On 18. Mar 2020, at 15:40, Massimiliano Gubinelli <m.gubinelli@gmail.com> wrote:
> > 
> > Good point with dynamic-wind. Does it pass along also multiple values or has the same problem?
> > 
> 
> Does not work...
> 
> mgubi@Ulrike guile3-usr % bin/guile
> GNU Guile 3.0.1
> Copyright (C) 1995-2020 Free Software Foundation, Inc.
> 
> Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'.
> This program is free software, and you are welcome to redistribute it
> under certain conditions; type `,show c' for details.
> 
> Enter `,help' for help.
> scheme@(guile-user)> (call-with-values (lambda ()
>  (dynamic-wind (lambda () (display "initialize\n"))
>   (lambda () (let ((a (values "a" "b" "c"))) a))
               ^^^^^^ HERE
>   (lambda () (display "finalize\n"))))
>   (lambda body body))
> initialize
> finalize
> $1 = ("a")
> scheme@(guile-user)> 
> 
> Isn't this a bug??? In my view it breaks composability of scheme code.

Above, marked with HERE is the crocodile eating
your other values.

If you instead do, in that line

  (lambda () (values "a" "b" "c"))

then you get ("a" "b" "c").

The let binding construct only binds one value. There's a
"let-values" for that.

Cheers
-- tomás

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

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

* Re: question about values
  2020-03-18 15:08               ` tomas
@ 2020-03-18 15:34                 ` Massimiliano Gubinelli
  0 siblings, 0 replies; 11+ messages in thread
From: Massimiliano Gubinelli @ 2020-03-18 15:34 UTC (permalink / raw)
  To: tomas; +Cc: guile-user, Matt Wette

Yes. Sorry. My bad, I had coded by copy&paste my previous example and is obviously not going to work.

Indeed dynamic-wind works as it should: 

mgubi@Ulrike guile3-usr % bin/guile
GNU Guile 3.0.1
Copyright (C) 1995-2020 Free Software Foundation, Inc.

Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'.
This program is free software, and you are welcome to redistribute it
under certain conditions; type `,show c' for details.

Enter `,help' for help.
scheme@(guile-user)> (call-with-values (lambda ()
 (dynamic-wind (lambda () (display "initialize\n"))
  (lambda () (values "a" "b" "c"))
  (lambda () (display "finalize\n"))))
  (lambda body body))
initialize
finalize
$2 = ("a" "b" "c")


It seems to me a very good solution to my problem. Thanks a lot to all!

Max



> On 18. Mar 2020, at 16:08, tomas@tuxteam.de wrote:
> 
> On Wed, Mar 18, 2020 at 03:48:03PM +0100, Massimiliano Gubinelli wrote:
>> 
>>> On 18. Mar 2020, at 15:40, Massimiliano Gubinelli <m.gubinelli@gmail.com> wrote:
>>> 
>>> Good point with dynamic-wind. Does it pass along also multiple values or has the same problem?
>>> 
>> 
>> Does not work...
>> 
>> mgubi@Ulrike guile3-usr % bin/guile
>> GNU Guile 3.0.1
>> Copyright (C) 1995-2020 Free Software Foundation, Inc.
>> 
>> Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'.
>> This program is free software, and you are welcome to redistribute it
>> under certain conditions; type `,show c' for details.
>> 
>> Enter `,help' for help.
>> scheme@(guile-user)> (call-with-values (lambda ()
>> (dynamic-wind (lambda () (display "initialize\n"))
>>  (lambda () (let ((a (values "a" "b" "c"))) a))
>               ^^^^^^ HERE
>>  (lambda () (display "finalize\n"))))
>>  (lambda body body))
>> initialize
>> finalize
>> $1 = ("a")
>> scheme@(guile-user)> 
>> 
>> Isn't this a bug??? In my view it breaks composability of scheme code.
> 
> Above, marked with HERE is the crocodile eating
> your other values.
> 
> If you instead do, in that line
> 
>  (lambda () (values "a" "b" "c"))
> 
> then you get ("a" "b" "c").
> 
> The let binding construct only binds one value. There's a
> "let-values" for that.
> 
> Cheers
> -- tomás




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

end of thread, other threads:[~2020-03-18 15:34 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2020-03-17 23:50 question about values Massimiliano Gubinelli
2020-03-18  6:12 ` Taylan Kammer
2020-03-18  9:55   ` Massimiliano Gubinelli
2020-03-18 11:06     ` Massimiliano Gubinelli
2020-03-18 12:39     ` Matt Wette
2020-03-18 13:11       ` Massimiliano Gubinelli
2020-03-18 14:06         ` John Cowan
2020-03-18 14:40           ` Massimiliano Gubinelli
2020-03-18 14:48             ` Massimiliano Gubinelli
2020-03-18 15:08               ` tomas
2020-03-18 15:34                 ` Massimiliano Gubinelli

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