unofficial mirror of guile-user@gnu.org 
 help / color / mirror / Atom feed
From: Chris Vine <vine35792468@gmail.com>
To: Mark H Weaver <mhw@netris.org>
Cc: guile-user@gnu.org
Subject: Re: Threading / Pipe Macro
Date: Sun, 7 Jul 2019 21:16:13 +0100	[thread overview]
Message-ID: <20190707211613.4a8a637da93e592b4f737a7f@gmail.com> (raw)
In-Reply-To: <871rz1fxr7.fsf@netris.org>

On Sun, 07 Jul 2019 15:30:36 -0400
Mark H Weaver <mhw@netris.org> wrote:
> Hi Chris,
> 
> Chris Vine <vine35792468@gmail.com> 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.

How strange.  Both your and my macro gives 'global-t' when I test them,
which is the result I would expect.  (Maybe I am missing something here,
but a result of 'inner-t' would seem to me to imply unhygiene.)

However if I change my macro to manipulate syntax objects I do get
'inner-t'

(define-syntax -->
  (lambda (x)
    (syntax-case x ()
      [(_ exp0 exp1 ...)
       (let ([reversed (reverse #'(exp0 exp1 ...))])
	 (with-syntax
	     ([out
	       (let loop ([first (car reversed)]
			  [rest (cdr reversed)])
		 (if (null? rest)
		     first
		     (syntax-case first ()
		       [(func arg0 ...)
			(append #'(func arg0 ...)
				(list (loop (car rest) (cdr rest))))])))])
	   #'out))])))

I need to think more about this and/or reproduce this later.

This is with guile-2.2.6 by the way.

Chris



  reply	other threads:[~2019-07-07 20:16 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-07-07 10:42 Threading / Pipe Macro Zelphir Kaltstahl
2019-07-07 18:32 ` Chris Vine
2019-07-07 18:39   ` Chris Vine
2019-07-07 19:30   ` Mark H Weaver
2019-07-07 20:16     ` Chris Vine [this message]
2019-07-07 22:24       ` Mark H Weaver
2019-07-08  0:10         ` Chris Vine
2019-07-07 22:25       ` Chris Vine
2019-07-07 22:46         ` Mark H Weaver
2019-07-08  1:09           ` Mark H Weaver
2019-07-08  0:49 ` Erik Edrosa
2019-07-08  7:39   ` Linus Björnstam
2019-07-08 21:26   ` Zelphir Kaltstahl

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/guile/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20190707211613.4a8a637da93e592b4f737a7f@gmail.com \
    --to=vine35792468@gmail.com \
    --cc=guile-user@gnu.org \
    --cc=mhw@netris.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).