From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!.POSTED!not-for-mail From: Chris Marusich Newsgroups: gmane.lisp.guile.user Subject: Re: Multiple values passed as single argument to procedure Date: Fri, 01 Sep 2017 12:39:04 -0700 Message-ID: <87o9quxl7r.fsf@gmail.com> NNTP-Posting-Host: blaine.gmane.org Mime-Version: 1.0 Content-Type: multipart/signed; boundary="==-=-="; micalg=pgp-sha256; protocol="application/pgp-signature" X-Trace: blaine.gmane.org 1504294812 25274 195.159.176.226 (1 Sep 2017 19:40:12 GMT) X-Complaints-To: usenet@blaine.gmane.org NNTP-Posting-Date: Fri, 1 Sep 2017 19:40:12 +0000 (UTC) User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/25.2 (gnu/linux) To: guile-user@gnu.org Original-X-From: guile-user-bounces+guile-user=m.gmane.org@gnu.org Fri Sep 01 21:40:02 2017 Return-path: Envelope-to: guile-user@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by blaine.gmane.org with esmtp (Exim 4.84_2) (envelope-from ) id 1dnrn7-0005ID-9Y for guile-user@m.gmane.org; Fri, 01 Sep 2017 21:39:45 +0200 Original-Received: from localhost ([::1]:57109 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dnrnE-0005eO-Ah for guile-user@m.gmane.org; Fri, 01 Sep 2017 15:39:52 -0400 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:44564) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dnrmi-0005db-Dj for guile-user@gnu.org; Fri, 01 Sep 2017 15:39:25 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dnrmd-0003bi-Eu for guile-user@gnu.org; Fri, 01 Sep 2017 15:39:20 -0400 Original-Received: from mail-pg0-x22e.google.com ([2607:f8b0:400e:c05::22e]:35073) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1dnrmd-0003aD-4L for guile-user@gnu.org; Fri, 01 Sep 2017 15:39:15 -0400 Original-Received: by mail-pg0-x22e.google.com with SMTP id 63so3133676pgc.2 for ; Fri, 01 Sep 2017 12:39:13 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:subject:in-reply-to:date:message-id:user-agent:mime-version; bh=QXyxLmERnL6C4UetNnsoK4Xw1WOKoJobbSILwhB89ow=; b=g6SgJzEWbMulCdCJ2EAJgzRgiH/twAhYV4oihDGf5nXeJrgeW7029kKCGqlbpmIaFl wy/7txdDrhX2v7ZLG+qDvy385oa7NugqCE/qOy28v3DRrWYhmZYomCqkP7hz4ooNjvuv 4BdfcfmxmqZOoAWacb7//3OazX4PxDpzhiiqQR1oAyCuJemRfNYXZUhulpt5toythWRY chC0DQLAFzXVs6QoWEfcErE0dJIIwVd1+vhccbxMtDm9ZTbQ7UPA5U8IqLez7DLwaAfS pkx2XvnKbJub/mzRjdfmDTp/Tr2n/wJbBX74Au0rK+QlABTI3soFBuaOwtTw7Y2k6eTk XAwg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:in-reply-to:date:message-id :user-agent:mime-version; bh=QXyxLmERnL6C4UetNnsoK4Xw1WOKoJobbSILwhB89ow=; b=DIW+uRLz4USVZb4BrXKorixbnMaDyLvuGsjfCk45GR5+Wnhy6diOvhodINXjqDHrBX ZUHKbudtaxxwBSspxnpUaGk/ucZ9+Y1ftrQzRzTOOrnMn+6YKnfebrEFL8lfqI+tVC3Y 9gr4CEG40Wj4fwHo2Tjpb5hxT6gAMjlKUsBjmAyseLcsW/Pg+I3NVrBz5fQDgqN8WEe+ F9wUFPc1cn7wBtuhBM5hl8Y1dlXzo8jEwGv+FxfJtybmh750YSSvlU/jKvhQGirLuSco uXzqiaRTbmc8ESCVXzwyVZq937lw4O3s1sRpdR9ejHIXOSOzQifM1QHfL2H00/IKlRlC t2DQ== X-Gm-Message-State: AHPjjUjNJN/FD8+OHooOtlhzyT94t+uKOg0DJPb8az2ncCBxZbi0+BFt 3sC3ATIEXtpkhdqpfRI= X-Google-Smtp-Source: ADKCNb5G3KCJ2X8S+svOvlDNr+xhXc3c+sKjY+ec1/FVpfCA5f38pTfAoZXWaRuLoHt34VBTTXqJRA== X-Received: by 10.98.213.197 with SMTP id d188mr3530603pfg.33.1504294752311; Fri, 01 Sep 2017 12:39:12 -0700 (PDT) Original-Received: from garuda ([172.58.40.176]) by smtp.gmail.com with ESMTPSA id a68sm1126085pfc.162.2017.09.01.12.39.10 for (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Fri, 01 Sep 2017 12:39:11 -0700 (PDT) In-Reply-To: 87mv9dy5wb.fsf@gmail.com X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2607:f8b0:400e:c05::22e X-BeenThere: guile-user@gnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: General Guile related discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: guile-user-bounces+guile-user=m.gmane.org@gnu.org Original-Sender: "guile-user" Xref: news.gmane.org gmane.lisp.guile.user:14086 Archived-At: --==-=-= Content-Type: multipart/mixed; boundary="=-=-=" --=-=-= Content-Type: text/plain Content-Transfer-Encoding: quoted-printable 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 =2D-=20 Chris --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0001-doc-Discuss-Guile-specific-behavior-related-to-multi.patch Content-Transfer-Encoding: quoted-printable From=20c14d283b5e830eb0f9054e51986545b9ba15f247 Mon Sep 17 00:00:00 2001 From: Chris Marusich 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. =2D-- 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 =2D-- a/doc/ref/api-control.texi +++ b/doc/ref/api-control.texi @@ -902,6 +902,36 @@ procedure body. @code{call-with-values} combines a pr= ocedure returning multiple values with a procedure which accepts these values as parameters. =20 +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 =3D 1 +$2 =3D 2 +scheme@@(guile-user)> (list (values 1 2)) +$3 =3D (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 =2D-- 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} t= hat 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 =2Dcompatible 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. =20 @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 =3D 1 +$2 =3D 2 +scheme@@(guile-user)> (define composition (compose list g)) +scheme@@(guile-user)> (composition) +$3 =3D (1 2) +scheme@@(guile-user)> (list (g)) +$4 =3D (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 =3D (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 =20 @deffn {Scheme Procedure} identity x =2D-=20 2.14.1 --=-=-=-- --==-=-= Content-Type: application/pgp-signature; name="signature.asc" -----BEGIN PGP SIGNATURE----- iQIzBAEBCAAdFiEEy/WXVcvn5+/vGD+x3UCaFdgiRp0FAlmpt1gACgkQ3UCaFdgi Rp2KiQ//fgEigsa2nqm89bWV8CygcxxJnW8+zKLlYfSIDEyb/637QyeEgSjgnqCn bC776tBl4fm/8ctNJZ2bvTkp3q+LLJ7vIXy8Rbj4CgyMtexkSntQbgJhuKd+lA5+ mIq1wy5oISBTJMLJYlDrMcuBYxIhUUsa4dqbzxpJD5eFkOVn+LweSafbY+XH0S4F Tst24TNMxiicLMzICZZkTWiNmRtrmBTX0hY4LCWXaos9MH4gvVyDrsv/Gl4dIjVJ wImEyRfocY8pWraBI53q9+cGvgEq/xuSBxZG1+cWEBPQ/BQ3EqiyIfVM8wCcfM5b 5QTG1Xc/AMQqQ/8QEXb1InbmssMRmw50VDHNmXD0wwinHKU+em0+ml8RIUi8riMi P/UhM1GnMHPoy6YvHQmVW+xJhWX1WQ63bCyfLua4EWEwq5cbWaFiHiNenshOxntW 7OaVTpxG2get0AjQDUVOZKj0T9EAHwa4zlWt9yysUszTg0EIEOxwDViCcbVoHX3R zZNKuo3MFwlqdvf/uWOJ+ED+UTY9UuyWaxTM91YCdlU5O+w/X5vqDVmuHvUWkFV4 mLQCKXhVhsAspAv+y2PzFpPLY8bX8yUUmvwYS04pqceRyBvj5jYuhAczKW9l+wAu 5rWCSZZd3ks/tRZgRlNnDzpYtKZMri52bOEC2bBL6Jc+XDVum80= =ABb8 -----END PGP SIGNATURE----- --==-=-=--