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.bugs Subject: bug#30237: Generalizing =?UTF-8?Q?=E2=80=98and=3D>=E2=80=99?= Date: Wed, 24 Jan 2018 10:01:44 -0500 Message-ID: <877es7ti5j.fsf@netris.org> References: <877es731ar.fsf@gnu.org> NNTP-Posting-Host: blaine.gmane.org Mime-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable X-Trace: blaine.gmane.org 1516806090 8327 195.159.176.226 (24 Jan 2018 15:01:30 GMT) X-Complaints-To: usenet@blaine.gmane.org NNTP-Posting-Date: Wed, 24 Jan 2018 15:01:30 +0000 (UTC) User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/25.3 (gnu/linux) Cc: 30237@debbugs.gnu.org To: Mathieu Lirzin Original-X-From: bug-guile-bounces+guile-bugs=m.gmane.org@gnu.org Wed Jan 24 16:01:26 2018 Return-path: Envelope-to: guile-bugs@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 1eeMYF-0001hi-5Z for guile-bugs@m.gmane.org; Wed, 24 Jan 2018 16:01:23 +0100 Original-Received: from localhost ([::1]:54066 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1eeMaF-0000ye-Lr for guile-bugs@m.gmane.org; Wed, 24 Jan 2018 10:03:27 -0500 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:35149) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1eeMZw-0000up-Cb for bug-guile@gnu.org; Wed, 24 Jan 2018 10:03:16 -0500 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1eeMZr-0003rK-Cs for bug-guile@gnu.org; Wed, 24 Jan 2018 10:03:08 -0500 Original-Received: from debbugs.gnu.org ([208.118.235.43]:33301) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1eeMZr-0003rG-93 for bug-guile@gnu.org; Wed, 24 Jan 2018 10:03:03 -0500 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1eeMZq-0000hR-1a for bug-guile@gnu.org; Wed, 24 Jan 2018 10:03:02 -0500 X-Loop: help-debbugs@gnu.org Resent-From: Mark H Weaver Original-Sender: "Debbugs-submit" Resent-CC: bug-guile@gnu.org Resent-Date: Wed, 24 Jan 2018 15:03:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 30237 X-GNU-PR-Package: guile X-GNU-PR-Keywords: Original-Received: via spool by 30237-submit@debbugs.gnu.org id=B30237.15168061432643 (code B ref 30237); Wed, 24 Jan 2018 15:03:01 +0000 Original-Received: (at 30237) by debbugs.gnu.org; 24 Jan 2018 15:02:23 +0000 Original-Received: from localhost ([127.0.0.1]:41198 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1eeMZD-0000gZ-Ch for submit@debbugs.gnu.org; Wed, 24 Jan 2018 10:02:23 -0500 Original-Received: from world.peace.net ([50.252.239.5]:60798) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1eeMZB-0000gL-9u for 30237@debbugs.gnu.org; Wed, 24 Jan 2018 10:02:21 -0500 Original-Received: from pool-72-93-27-251.bstnma.east.verizon.net ([72.93.27.251] helo=jojen) by world.peace.net with esmtpsa (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.89) (envelope-from ) id 1eeMZ5-0004T5-3b; Wed, 24 Jan 2018 10:02:15 -0500 In-Reply-To: <877es731ar.fsf@gnu.org> (Mathieu Lirzin's message of "Wed, 24 Jan 2018 13:10:20 +0100") X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 208.118.235.43 X-BeenThere: bug-guile@gnu.org List-Id: "Bug reports for GUILE, GNU's Ubiquitous Extension Language" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-guile-bounces+guile-bugs=m.gmane.org@gnu.org Original-Sender: "bug-guile" Xref: news.gmane.org gmane.lisp.guile.bugs:8980 Archived-At: Hi Mathieu, Mathieu Lirzin writes: > Here is a proposal for generalizing =E2=80=98and=3D>=E2=80=99 to a pipeli= ne of procedures. > It acts like a =E2=80=9Cbind=E2=80=9D operator in an ad-hoc =E2=80=9CMayb= e=E2=80=9D monad which uses #f > to represent the absence of value. Not sure if it is useful in > practice, but it feels like a natural generalization. > > The current definition is the following: > > (define (and=3D> value procedure) > (and value (procedure value))) > > Here is my proposition: > > (define-syntax and=3D> > (syntax-rules () > ((_) #t) > ((_ val) val) > ((_ val proc) > (and val (proc val))) > ((_ val proc proc* ...) > (and=3D> (and val (proc val)) proc* ...)))) Be careful, macros are different than procedures! Instead of binding values to variables, they bind _unevaluated_ forms to pattern variables. So 'val' is a misleading name for the first operand of the macro above. In fact, what's being bound there is an _expression_, and you are then expanding this into something that contains two copies of that expression. So, for example: (and=3D> (compile-webkitgtk) test install) expands into: (and=3D> (and (compile-webkitgtk) (test (compile-webkitgtk))) install) which expands into: (and (and (compile-webkitgtk) (test (compile-webkitgtk))) (install (and (compile-webkitgtk) (test (compile-webkitgtk))))) So you end up compiling webkitgtk 4 times, and testing it twice, before finally installing it. More generally, if you pass N+1 operands, the first operand will be evaluated 2^N times. The other problem is that 'and=3D>' is currently a procedure, and you're replacing it with a macro. There are a couple of issues with this. One is that procedures are first-class objects in Scheme, but macros aren't. Procedures can be passed as arguments to procedures, stored in data structures, etc, but macros cannot. For example, if 'and=3D>' is a procedure, you can write: (map and=3D> vals procs) but you can't do this if 'and=3D>' is a macro. The other problem with changing 'and=3D>' to a macro is that this effectively changes the ABI of Guile, which we can't do within a stable release series (2.2.x). Existing .go files that use 'and=3D>' were compiled to generate a normal procedure call for 'and=3D>', and if that procedure no longer exists then the code will break. This change requires all users of 'and=3D>' to be recompiled. > Let me know if such change is welcome or not, so I can provide a > complete patch including documentation. I think it's worth considering something along these lines for the 'master' branch which will eventually become Guile 3, although in order to support existing callers that expect 'and=3D>' to be a first-class procedure, we might want to arrange for a bare 'and=3D>' to expand into a reference to a first-class procedure that does the same job, similar to what we do with 'define-inlinable'. The other option would be to implement your enhanced 'and=3D>' as a normal procedure using case-lambda, maybe something like this: (define and=3D> (case-lambda ((val proc) (and val (proc val))) ((val . procs) (let loop ((val val) (procs procs)) (if (null? procs) val (and val (loop ((car procs) val) (cdr procs)))))) (() #t))) The first case is not strictly needed, but is included as an optimization to avoid heap-allocating a list for the 'procs' rest argument in the common case of two arguments. The second case is implemented as a loop instead of a recursive call to 'and=3D>', to prevent repeatedly heap-allocating the rest list on each iteration, which would lead to O(N^2) allocations for N arguments. It would be nicer to use 'match' here, but since 'and=3D>' is defined early in boot-9.scm, we must restrict ourselves to core functionality in its implementation. I'm not sure if it makes sense to include the final (nullary) case. Unlike 'and', 'or', '+', '*' and similar operations where every argument is treated uniformally, in this case the first argument is qualitatively different than the others. Therefore, it seems to me that this procedure naturally generalizes down to 1 argument, but no further. Finally, there still some question in my mind whether this generalization would be useful in practice. Have you found a real-world use case where this generalized 'and=3D>' makes life easier? Do you know about SRFI-2 (and-let*)? How would that work for your use case? Regards, Mark