unofficial mirror of guile-user@gnu.org 
 help / color / mirror / Atom feed
* Multiple values passed as single argument to procedure
@ 2017-06-11  7:56 Chris Marusich
  2017-06-11  8:28 ` David Kastrup
  2017-06-11 20:36 ` Mark H Weaver
  0 siblings, 2 replies; 18+ messages in thread
From: Chris Marusich @ 2017-06-11  7:56 UTC (permalink / raw)
  To: guile-user

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

Hi,

I've noticed that when one passes multiple values as a single argument
to a procedure, only the first value gets used.  Is this expected?
Here's an example:

--8<---------------cut here---------------start------------->8---
$ guile
GNU Guile 2.2.2
Copyright (C) 1995-2017 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)> (define (proc x) x)
scheme@(guile-user)> (proc (values 1 2))
$1 = 1
scheme@(guile-user)> 
--8<---------------cut here---------------end--------------->8---

I've looked in a few places to try to figure out the answer to this
question, but I haven't found much.  In addition to the guile-devel and
guile-user email list archives, I've checked the following sections in
the manual:

(guile) Binding Multiple Values
(guile) Lambda
(guile) Fly Evaluation
(guile) Compiled Procedures
(guile) Expression Syntax

However, I did find the following information in R6RS (Section 5.8:
"Multiple return values"), which seems possibly relevant:

"Not all continuations accept any number of values. For example, a
continuation that accepts the argument to a procedure call is guaranteed
to accept exactly one value.  The effect of passing some other number of
values to such a continuation is unspecified."

-- 
Chris

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 832 bytes --]

^ permalink raw reply	[flat|nested] 18+ messages in thread
* Re: Multiple values passed as single argument to procedure
@ 2017-09-01 19:39 Chris Marusich
  0 siblings, 0 replies; 18+ messages in thread
From: Chris Marusich @ 2017-09-01 19:39 UTC (permalink / raw)
  To: guile-user


[-- Attachment #1.1: Type: text/plain, Size: 821 bytes --]


Earlier, I wrote:

> OK.  I'll submit a patch later this week to update the manual with
> information taken from this email thread.  Hopefully that will help
> clarify the behavior for others in the future.

Please find the promised patch attached.  It's still this week, isn't
it? :-)

As a Guile newbie, I found the behavior related to multiple values to be
very confusing at first.  I've tried to explain things in a way that is
accurate, easy for a newbie to understand, and points the curious reader
to appropriate resources for further reading.  Hopefully, this small
contribution will help to clarify the behavior for future Guile newbies.

For reference, this patch is follow-up to the following email thread:

https://lists.gnu.org/archive/html/guile-user/2017-06/msg00043.html

-- 
Chris

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1.2: 0001-doc-Discuss-Guile-specific-behavior-related-to-multi.patch --]
[-- Type: text/x-patch, Size: 5698 bytes --]

From c14d283b5e830eb0f9054e51986545b9ba15f247 Mon Sep 17 00:00:00 2001
From: Chris Marusich <cmmarusich@gmail.com>
Date: Thu, 31 Aug 2017 23:46:25 -0700
Subject: [PATCH] doc: Discuss Guile-specific behavior related to multiple
 values.

* doc/ref/api-control.texi (Multiple Values): Explain (and caution
  against relying upon) Guile-specific behavior when passing multiple
  values as a single argument to a procedure.

* doc/ref/api-procedures.texi (Higher-Order Functions): Explain (and
  caution against relying upon) potentially counter-intuitive behavior
  that can arise when attempting to mimic the behavior of the 'compose'
  procedure by naively chaining together multi-valued procedure calls.
---
 doc/ref/api-control.texi    | 30 +++++++++++++++++++++++++++
 doc/ref/api-procedures.texi | 50 ++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 79 insertions(+), 1 deletion(-)

diff --git a/doc/ref/api-control.texi b/doc/ref/api-control.texi
index 2d696ea89..46da2f17f 100644
--- a/doc/ref/api-control.texi
+++ b/doc/ref/api-control.texi
@@ -902,6 +902,36 @@ procedure body.  @code{call-with-values} combines a procedure returning
 multiple values with a procedure which accepts these values as
 parameters.
 
+You might sometimes be tempted to try to pass multiple values as a
+single argument to a procedure (e.g., when directly passing the output
+of one procedure call into another as input).  This works fine for
+single values, but caution is required when multiple values are
+involved.  The correct way to pass multiple values as arguments to a
+procedure is to use @code{call-with-values} or something else that uses
+it, such as @code{let-values} (@pxref{SRFI-11}) or @code{compose}
+(@pxref{Higher-Order Functions}).  If you attempt to pass multiple
+values as a single argument to a procedure, Guile will only use the
+first value as the argument.  For example, consider the following:
+
+@example
+scheme@@(guile-user)> (values 1 2)
+$1 = 1
+$2 = 2
+scheme@@(guile-user)> (list (values 1 2))
+$3 = (1)
+@end example
+
+Here, the @code{list} procedure is being called with a single argument.
+Therefore, even though the expression @code{(values 1 2)} evaluates to
+multiple values, Guile will only use the first value as the argument, so
+the result is the same as if we had written @code{(list 1)}.
+
+This behavior is specific to the Guile implementation of Scheme.  In
+R6RS, the behavior when attempting to pass multiple values as a single
+argument to a procedure (and in some other situations, too) is
+explicitly left unspecified.  Other implementations might behave
+differently, so you should think twice before relying upon it.
+
 @rnindex values
 @deffn {Scheme Procedure} values arg @dots{}
 @deffnx {C Function} scm_values (args)
diff --git a/doc/ref/api-procedures.texi b/doc/ref/api-procedures.texi
index df24178f9..bf97f7038 100644
--- a/doc/ref/api-procedures.texi
+++ b/doc/ref/api-procedures.texi
@@ -684,7 +684,10 @@ Return a procedure with the same arity as @var{proc} that returns the
 Compose @var{proc1} with the procedures @var{proc2} @dots{}  such that
 the last @var{proc} argument is applied first and @var{proc1} last, and
 return the resulting procedure.  The given procedures must have
-compatible arity.
+compatible arity; the first value returned by procedure @code{N} will be
+passed into procedure @code{N-1} as its first argument, the second value
+returned by procedure @code{N} will be passed into procedure @code{N-1}
+as its second argument, etc.
 
 @lisp
 (procedure? (compose 1+ 1-)) @result{} #t
@@ -695,6 +698,51 @@ compatible arity.
 ((compose zip unzip2) '((1 2) (a b)))
                              @result{} ((1 2) (a b))
 @end lisp
+
+When a procedure other than @var{proc1} returns multiple values, the
+behavior observed when calling the procedures one after another might
+differ from the behavior observed when calling their composition,
+depending on how the procedures are called.  This can lead to
+potentially counter-intuitive results like the following:
+
+@example
+scheme@@(guile-user)> (define (g) (values 1 2))
+scheme@@(guile-user)> (g)
+$1 = 1
+$2 = 2
+scheme@@(guile-user)> (define composition (compose list g))
+scheme@@(guile-user)> (composition)
+$3 = (1 2)
+scheme@@(guile-user)> (list (g))
+$4 = (1)
+scheme@@(guile-user)>
+@end example
+
+At first blush, it might seem intuitive that the expressions
+@code{(composition)} and @code{(list (g))} ought to evaluate to the same
+result.  This intuition would be correct if the procedure @code{g}
+returned only a single value.  However, it returns multiple values, and
+when you try to pass multiple values as a single argument to a
+procedure, Guile will only use the first value as the argument
+(@pxref{Multiple Values}).  Therefore, the result of evaluating
+@code{(list (g))} is the same as if we had written @code{(list 1)}.  It
+is not a correct composition, and you should think twice before relying
+on this Guile-specific behavior.
+
+It is possible to correctly compose procedures like these without using
+@code{compose}, but it requires the use of @code{call-with-values} or
+something else that uses it.  For example, the following correctly
+composes @code{list} with @code{g}:
+
+@example
+scheme@@(guile-user)> (call-with-values g list)
+$5 = (1 2)
+@end example
+
+In fact, this is essentially what the implementation of @code{compose}
+does: it recursively uses @code{call-with-values} to correctly compose
+all the functions.
+
 @end deffn
 
 @deffn {Scheme Procedure} identity x
-- 
2.14.1


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 832 bytes --]

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

end of thread, other threads:[~2017-09-01 19:39 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-06-11  7:56 Multiple values passed as single argument to procedure Chris Marusich
2017-06-11  8:28 ` David Kastrup
2017-06-11 20:36 ` Mark H Weaver
2017-06-11 21:31   ` Mark H Weaver
2017-06-12  0:19   ` Chris Marusich
2017-06-12  4:25     ` Mark H Weaver
2017-06-12  8:19       ` Chris Marusich
2017-06-12  8:55         ` Neil Jerram
2017-06-12  9:48           ` Neil Jerram
2017-06-12  9:39         ` David Kastrup
2017-06-12 11:31           ` Mark H Weaver
2017-06-12 14:24             ` David Kastrup
2017-06-13  2:26               ` Mark H Weaver
2017-06-13  3:09                 ` Mark H Weaver
2017-06-13  3:45                 ` Mark H Weaver
2017-06-13 11:17                 ` dsmich
2017-06-26 11:25                   ` Alex Vong
  -- strict thread matches above, loose matches on Subject: below --
2017-09-01 19:39 Chris Marusich

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