From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!.POSTED.blaine.gmane.org!not-for-mail From: Mark H Weaver Newsgroups: gmane.lisp.guile.user Subject: Re: Threading / Pipe Macro Date: Sun, 07 Jul 2019 15:30:36 -0400 Message-ID: <871rz1fxr7.fsf@netris.org> References: <5f08685b-be5b-e584-af54-9f4244039b1a@gmail.com> <20190707193259.434e1a816c551ece292f45da@gmail.com> Mime-Version: 1.0 Content-Type: text/plain Injection-Info: blaine.gmane.org; posting-host="blaine.gmane.org:195.159.176.226"; logging-data="135509"; mail-complaints-to="usenet@blaine.gmane.org" User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/26.1 (gnu/linux) Cc: guile-user@gnu.org To: Chris Vine Original-X-From: guile-user-bounces+guile-user=m.gmane.org@gnu.org Sun Jul 07 21:31:26 2019 Return-path: Envelope-to: guile-user@m.gmane.org Original-Received: from lists.gnu.org ([209.51.188.17]) by blaine.gmane.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.89) (envelope-from ) id 1hkCsf-000Z9y-UF for guile-user@m.gmane.org; Sun, 07 Jul 2019 21:31:26 +0200 Original-Received: from localhost ([::1]:36712 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hkCsf-0004w7-0A for guile-user@m.gmane.org; Sun, 07 Jul 2019 15:31:25 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]:49244) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hkCsP-0004tG-1U for guile-user@gnu.org; Sun, 07 Jul 2019 15:31:10 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1hkCsN-0001L6-Qu for guile-user@gnu.org; Sun, 07 Jul 2019 15:31:08 -0400 Original-Received: from world.peace.net ([64.112.178.59]:52900) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1hkCsN-0001KE-Mz for guile-user@gnu.org; Sun, 07 Jul 2019 15:31:07 -0400 Original-Received: from mhw by world.peace.net with esmtpsa (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.89) (envelope-from ) id 1hkCsM-0005QT-8X; Sun, 07 Jul 2019 15:31:06 -0400 In-Reply-To: <20190707193259.434e1a816c551ece292f45da@gmail.com> (Chris Vine's message of "Sun, 7 Jul 2019 19:32:59 +0100") X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 64.112.178.59 X-BeenThere: guile-user@gnu.org X-Mailman-Version: 2.1.23 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:15606 Archived-At: Hi Chris, Chris Vine writes: > I have a pipeline macro which sort-of mimics ML's |> pipeline operator > which I use a lot: > > (define-syntax -> > (lambda (x) > (syntax-case x () > [(k exp0 . exps) > (let* ([reversed (reverse (cons (syntax->datum #'exp0) > (syntax->datum #'exps)))] > [out (let loop ([first (car reversed)] > [rest (cdr reversed)]) > (if (null? rest) > first > (let ([func (car first)] > [args (cdr first)]) > (append `(,func ,@args) > (list (loop (car rest) (cdrrest)))))))]) > (datum->syntax #'k out))]))) > > Because all the macro does is to rearrange input forms, this is hygienic > without the need to manipulate syntax objects - you can convert to a datum, > rearrange and then convert back to a syntax object again, as above. This macro is *not* hygienic. The calls to 'syntax->datum' strip all of the context information from the syntax objects, and then build a new expression using raw S-expressions. The result is essentially the same as if you used 'define-macro'. This results various problems. For example: --8<---------------cut here---------------start------------->8--- scheme@(guile-user)> (define-syntax -> (lambda (x) (syntax-case x () [(k exp0 . exps) (let* ([reversed (reverse (cons (syntax->datum #'exp0) (syntax->datum #'exps)))] [out (let loop ([first (car reversed)] [rest (cdr reversed)]) (if (null? rest) first (let ([func (car first)] [args (cdr first)]) (append `(,func ,@args) (list (loop (car rest) (cdr rest)))))))]) (datum->syntax #'k out))]))) scheme@(guile-user)> (define t 'global-t) scheme@(guile-user)> (define-syntax-rule (foo x) (-> x (format #t "[t=~A] ~A\n" t))) scheme@(guile-user)> (let ((t 'inner-t)) (foo t)) [t=global-t] global-t $1 = #t scheme@(guile-user)> --8<---------------cut here---------------end--------------->8--- I recommend reformulating the -> macro using 'syntax-rules' as follows: --8<---------------cut here---------------start------------->8--- scheme@(guile-user)> (define-syntax -> (syntax-rules () ((-> exp) exp) ((-> exp ... (op args ...)) (op args ... (-> exp ...))))) scheme@(guile-user)> (let ((t 'inner-t)) (foo t)) [t=global-t] inner-t $8 = #t scheme@(guile-user)> --8<---------------cut here---------------end--------------->8--- This macro is hygienic, and also easier to comprehend (IMO). Of course, it could also be implemented using syntax-case. The key is to always work with the syntax objects. Whenever you use 'syntax->datum' on expressions that are not purely literals, you will be sacrificing hygiene. Regards, Mark