From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!.POSTED!not-for-mail From: Mark H Weaver Newsgroups: gmane.lisp.guile.user Subject: Re: Multiple values passed as single argument to procedure Date: Mon, 12 Jun 2017 00:25:08 -0400 Message-ID: <87a85d3k9n.fsf@netris.org> References: <87mv9fnejc.fsf@gmail.com> <87k24i2rev.fsf@netris.org> <87zidexdjw.fsf@gmail.com> NNTP-Posting-Host: blaine.gmane.org Mime-Version: 1.0 Content-Type: text/plain X-Trace: blaine.gmane.org 1497241551 32578 195.159.176.226 (12 Jun 2017 04:25:51 GMT) X-Complaints-To: usenet@blaine.gmane.org NNTP-Posting-Date: Mon, 12 Jun 2017 04:25:51 +0000 (UTC) User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/25.2 (gnu/linux) Cc: guile-user@gnu.org To: Chris Marusich Original-X-From: guile-user-bounces+guile-user=m.gmane.org@gnu.org Mon Jun 12 06:25:43 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 1dKGv9-00083h-C3 for guile-user@m.gmane.org; Mon, 12 Jun 2017 06:25:43 +0200 Original-Received: from localhost ([::1]:36056 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dKGvE-0007lU-It for guile-user@m.gmane.org; Mon, 12 Jun 2017 00:25:48 -0400 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:48333) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dKGur-0007lO-2v for guile-user@gnu.org; Mon, 12 Jun 2017 00:25:26 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dKGun-0006Hz-Ud for guile-user@gnu.org; Mon, 12 Jun 2017 00:25:25 -0400 Original-Received: from world.peace.net ([50.252.239.5]:43397) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1dKGun-0006Hs-PP for guile-user@gnu.org; Mon, 12 Jun 2017 00:25:21 -0400 Original-Received: from pool-72-93-27-151.bstnma.east.verizon.net ([72.93.27.151] helo=jojen) by world.peace.net with esmtpsa (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.84_2) (envelope-from ) id 1dKGum-0002n6-7q; Mon, 12 Jun 2017 00:25:20 -0400 In-Reply-To: <87zidexdjw.fsf@gmail.com> (Chris Marusich's message of "Sun, 11 Jun 2017 17:19:47 -0700") X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 50.252.239.5 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:13820 Archived-At: Hi Chris, Chris Marusich writes: > Mark H Weaver writes: > >> Use 'call-with-values', 'let-values', or 'receive' to call a procedure >> that returns multiple values (or no values). >> >> If you do not use one of the above forms (or a macro that expands to one >> of them) to call a procedure that returns multiple values, then Guile >> will discard all but the first result. Note that this is a >> Guile-specific extension. Other Scheme implementations may behave >> differently (e.g. report an error) if multiple values (or no values) are >> returned to a procedure call that was not done using one of the forms >> listed above. > > I see. So, this behavior is implementation-specific for Guile scheme. > > Is this behavior documented in the Guile reference manual? I looked, > but I couldn't find information about it. Indeed, I was not able to find it either. > So, it is not clear to me if one should rely on this behavior, or if > it is likely to change in the future. I would recommend against relying on this behavior, mainly because I would consider it a bit sloppy. However, I also think it's very unlikely that we would ever remove this extension, because I don't anticipate a compelling reason to remove it, and it would surely break existing code. > I was hoping to find this behavior documented in either > "(guile) Multiple Values" or somewhere in "(guile) About Procedures". > Perhaps there's a better location. In any case, I think it would be > helpful if this were documented in the manual. Agreed. "(guile) Multiple Values" is probably the appropriate place. > Here's another question. I've also noticed that when the 'list' > procedure is composed with a procedure f that returns multiple values, > the list that gets returned when calling the composition differs from > the list that results when "manually" invoking the same composition. An > example will clarify what I mean: > > --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 (f . _) (values 1 2)) > scheme@(guile-user)> (f) > $1 = 1 > $2 = 2 > scheme@(guile-user)> (define g (compose list f)) > scheme@(guile-user)> (g) > $3 = (1 2) > scheme@(guile-user)> (list (f)) > $4 = (1) > scheme@(guile-user)> > --8<---------------cut here---------------end--------------->8--- > > In the above, I was surprised to find that $3 was not the same as $4. > To put this another way, I was surprised to find that the composition > via 'compose' (which returned $3) did not behave the same as the > 'manual' composition (which returned $4). What's going on here? The problem is that you implemented your 'manual' composition in a way that allows only one value to pass between the two procedures. Remember that when a procedure call is made without 'call-with-values' (or some macro that uses it), and is not in tail position, then all but the first return value is discarded. That's what's happening in your call to 'f' in (list (f)). The call (f) is neither in tail position nor called using 'call-with-values', so only one of its values is kept. Try this instead: (let-values ((vals (f))) (apply list vals)) Or, more simply in the case where 'f' takes no arguments: (call-with-values f list) I suppose you are thinking of 'compose' as being implemented like this: (define (compose f g) (lambda (x) (f (g x)))) and that's a fine definition for unary procedures that return a single argument. Here's one way to implement 'compose' that supports procedures of arbitrary arity that return an arbitrary number of values: (define (compose f g) (lambda args-for-g (let-values ((args-for-f (apply g args-for-g))) (apply f args-for-f)))) Using 'call-with-values', it looks like this: (define (compose f g) (lambda args (call-with-values (lambda () (apply g args)) f))) I should note that the simple unary-only version of 'compose' that I gave above produces more efficient procedures than the latter two, because no heap allocation is required during execution of the resulting procedure. The more general versions of 'compose' produce procedures that must allocate lists of arguments 'args', and 'args-for-f' and 'args-for-g' on the GC heap. The core Guile version of 'compose' is defined in ice-9/boot-9.scm. Mark