unofficial mirror of guix-devel@gnu.org 
 help / color / mirror / code / Atom feed
* Some macros to make package definitions prettier
@ 2015-02-25 16:42 Taylan Ulrich Bayırlı/Kammer
  2015-02-25 17:04 ` Thompson, David
                   ` (2 more replies)
  0 siblings, 3 replies; 16+ messages in thread
From: Taylan Ulrich Bayırlı/Kammer @ 2015-02-25 16:42 UTC (permalink / raw)
  To: guix-devel

I would propose the following macros to make package definitions
somewhat nicer:


;;; modify-phases

(define-syntax modify-phases
  (syntax-rules ()
    ((modify-phases phases mod-spec ...)
     (let* ((phases* phases)
            (phases* (%modify-phases phases* mod-spec))
            ...)
       phases*))))

(define-syntax %modify-phases
  (syntax-rules (delete replace add-before add-after)
    ((_ phases (delete old-phase-name))
     (alist-delete 'old-phase-name phases))
    ((_ phases (replace old-phase-name new-phase))
     (alist-replace 'old-phase-name new-phase phases))
    ((_ phases (add-before old-phase-name new-phase-name new-phase))
     (alist-cons-before 'old-phase-name 'new-phase-name new-phase phases))
    ((_ phases (add-after old-phase-name new-phase-name new-phase))
     (alist-cons-after 'old-phase-name 'new-phase-name new-phase phases))))

;;; Usage example:

(modify-phases '((foo . 0) (bar . 1) (baz . 2))
  (delete foo)
  (replace bar 'x)
  (add-before baz pre-baz 'y)) ;=> ((bar . x) (pre-baz . y) (baz . 2))


This has the following advantages:

- The order in which the phases are modified is top-down, where in our
  current style it's bottom-up which both distracts (IMO), and one may
  forget, as the chain grows and one forgets that it's indeed just a
  chain of function calls like (foo (bar (baz x))).

- Indentation doesn't keep growing as one adds more modifications.

- It's easier for Scheme-newcomers, though one might say alists are
  pretty simple and fundamental and should be learned immediately...


And secondly:

;;; phase-lambda

(define-syntax phase-lambda
  (syntax-rules ()
    ((phase-lambda ((arg (alist-entry ...))
                    ...)
       body ...)
     (lambda* (#:key arg ... #:allow-other-keys)
       (let-values (((alist-entry ...)
                     (let ((arg* arg))
                       (values
                        (assoc-ref arg* (symbol->string 'alist-entry))
                        ...)))
                    ...)
         body ...)))))

;;; Usage example:

(phase-lambda ((inputs (libx liby))
               (outputs (out)))
  ...)

;;; effectively equivalent to:

(lambda* (#:key inputs outputs #:allow-other-keys)
  (let ((libx (assoc-ref inputs "libx"))
        (liby (assoc-ref inputs "liby"))
        (out (assoc-ref outputs "out")))
    ...))


This saves the usual boilerplate of '(#:key inputs outputs
#:allow-other-keys)' and the subsequent `assoc-ref' uses.  One might say
it's too specific because the phase procedures also receive non-alist
arguments (although one can add an argument clause like '(foo ())' and
it will work because no `assoc-ref' call will happen on `foo', though
that's a hack), but I looked at all occurrences of "#:key" in
gnu/packages/*.scm, and pure uses of `input' and/or `output' are
extremely dominant, such that it should be fine to fall back to a plain
`lambda*' in the remaining cases.


WDYT?

Taylan

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Some macros to make package definitions prettier
  2015-02-25 16:42 Some macros to make package definitions prettier Taylan Ulrich Bayırlı/Kammer
@ 2015-02-25 17:04 ` Thompson, David
  2015-02-25 17:06   ` Thompson, David
  2015-02-25 20:54   ` Taylan Ulrich Bayırlı/Kammer
  2015-02-25 18:12 ` Andreas Enge
  2015-02-25 23:32 ` Ludovic Courtès
  2 siblings, 2 replies; 16+ messages in thread
From: Thompson, David @ 2015-02-25 17:04 UTC (permalink / raw)
  To: Taylan Ulrich Bayırlı/Kammer; +Cc: guix-devel

On Wed, Feb 25, 2015 at 11:42 AM, Taylan Ulrich Bayırlı/Kammer
<taylanbayirli@gmail.com> wrote:
> I would propose the following macros to make package definitions
> somewhat nicer:

I've been thinking that we need some macros for this for awhile!
Thanks for getting the conversation started.

>
> ;;; modify-phases
>
> (define-syntax modify-phases
>   (syntax-rules ()
>     ((modify-phases phases mod-spec ...)
>      (let* ((phases* phases)
>             (phases* (%modify-phases phases* mod-spec))
>             ...)
>        phases*))))
>
> (define-syntax %modify-phases
>   (syntax-rules (delete replace add-before add-after)
>     ((_ phases (delete old-phase-name))
>      (alist-delete 'old-phase-name phases))
>     ((_ phases (replace old-phase-name new-phase))
>      (alist-replace 'old-phase-name new-phase phases))
>     ((_ phases (add-before old-phase-name new-phase-name new-phase))
>      (alist-cons-before 'old-phase-name 'new-phase-name new-phase phases))
>     ((_ phases (add-after old-phase-name new-phase-name new-phase))
>      (alist-cons-after 'old-phase-name 'new-phase-name new-phase phases))))
>
> ;;; Usage example:
>
> (modify-phases '((foo . 0) (bar . 1) (baz . 2))
>   (delete foo)
>   (replace bar 'x)
>   (add-before baz pre-baz 'y)) ;=> ((bar . x) (pre-baz . y) (baz . 2))
>
>
> This has the following advantages:
>
> - The order in which the phases are modified is top-down, where in our
>   current style it's bottom-up which both distracts (IMO), and one may
>   forget, as the chain grows and one forgets that it's indeed just a
>   chain of function calls like (foo (bar (baz x))).
>
> - Indentation doesn't keep growing as one adds more modifications.
>
> - It's easier for Scheme-newcomers, though one might say alists are
>   pretty simple and fundamental and should be learned immediately...

I like the top-down ordering and the linear structure rather than a
nested structure like we have currently.

I understand the temptation to name it 'modify-phases', but since this
macro applies to any alist, I think 'modify-alist' or something with
"alist" in the name would be more appropriate.

>
> And secondly:
>
> ;;; phase-lambda
>
> (define-syntax phase-lambda
>   (syntax-rules ()
>     ((phase-lambda ((arg (alist-entry ...))
>                     ...)
>        body ...)
>      (lambda* (#:key arg ... #:allow-other-keys)
>        (let-values (((alist-entry ...)
>                      (let ((arg* arg))
>                        (values
>                         (assoc-ref arg* (symbol->string 'alist-entry))
>                         ...)))
>                     ...)
>          body ...)))))
>
> ;;; Usage example:
>
> (phase-lambda ((inputs (libx liby))
>                (outputs (out)))
>   ...)
>
> ;;; effectively equivalent to:
>
> (lambda* (#:key inputs outputs #:allow-other-keys)
>   (let ((libx (assoc-ref inputs "libx"))
>         (liby (assoc-ref inputs "liby"))
>         (out (assoc-ref outputs "out")))
>     ...))
>
>
> This saves the usual boilerplate of '(#:key inputs outputs
> #:allow-other-keys)' and the subsequent `assoc-ref' uses.  One might say
> it's too specific because the phase procedures also receive non-alist
> arguments (although one can add an argument clause like '(foo ())' and
> it will work because no `assoc-ref' call will happen on `foo', though
> that's a hack), but I looked at all occurrences of "#:key" in
> gnu/packages/*.scm, and pure uses of `input' and/or `output' are
> extremely dominant, such that it should be fine to fall back to a plain
> `lambda*' in the remaining cases.

I'm not sure I like combining the alist destructuring part of this
macro.  IMO, 'phase-lambda' could just take care of the 'lambda*'
boilerplate, and maybe another macro ('alist-let'?) to reduce the
'assoc-ref' usage.

Implementation details aside, I think macros like these are very much
needed to reduce boilerplate and improve the readability of our
package recipes.

Thanks for sharing!

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Some macros to make package definitions prettier
  2015-02-25 17:04 ` Thompson, David
@ 2015-02-25 17:06   ` Thompson, David
  2015-02-25 19:27     ` Taylan Ulrich Bayırlı/Kammer
  2015-02-25 20:54   ` Taylan Ulrich Bayırlı/Kammer
  1 sibling, 1 reply; 16+ messages in thread
From: Thompson, David @ 2015-02-25 17:06 UTC (permalink / raw)
  To: Taylan Ulrich Bayırlı/Kammer; +Cc: guix-devel

On Wed, Feb 25, 2015 at 12:04 PM, Thompson, David
<dthompson2@worcester.edu> wrote:

> I understand the temptation to name it 'modify-phases', but since this
> macro applies to any alist, I think 'modify-alist' or something with
> "alist" in the name would be more appropriate.

Looking again, I see that the above isn't quite true.  The
'modify-phases' macro assumes that the keys of the alist are symbols
so that the user doesn't have to quote the phase names.

- Dave

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Some macros to make package definitions prettier
  2015-02-25 16:42 Some macros to make package definitions prettier Taylan Ulrich Bayırlı/Kammer
  2015-02-25 17:04 ` Thompson, David
@ 2015-02-25 18:12 ` Andreas Enge
  2015-02-25 19:46   ` Taylan Ulrich Bayırlı/Kammer
  2015-02-25 20:24   ` Thompson, David
  2015-02-25 23:32 ` Ludovic Courtès
  2 siblings, 2 replies; 16+ messages in thread
From: Andreas Enge @ 2015-02-25 18:12 UTC (permalink / raw)
  To: Taylan Ulrich Bayırlı/Kammer; +Cc: guix-devel

Hello,

thanks for sharing your suggestions!

On Wed, Feb 25, 2015 at 05:42:23PM +0100, Taylan Ulrich Bayırlı/Kammer wrote:
>   (delete foo)
>   (replace bar 'x)
>   (add-before baz pre-baz 'y)) ;=> ((bar . x) (pre-baz . y) (baz . 2))
> This has the following advantages:
> - The order in which the phases are modified is top-down, where in our
>   current style it's bottom-up which both distracts (IMO), and one may
>   forget, as the chain grows and one forgets that it's indeed just a
>   chain of function calls like (foo (bar (baz x))).
> - Indentation doesn't keep growing as one adds more modifications.

Actually, I do not like the imperative, non-functional style of these
syntax rules. For me, they rather obscure what is happening.

The indentation is just a question of style; in my first recipes, I did not
indent consecutive modifications of phases, which was just as readable,
I think (but this only works if you indent manually, and people disliked
the unorthodox (non-)indentation).

> (phase-lambda ((inputs (libx liby))
>                (outputs (out)))
>   ...)
> 
> ;;; effectively equivalent to:
> 
> (lambda* (#:key inputs outputs #:allow-other-keys)
>   (let ((libx (assoc-ref inputs "libx"))
>         (liby (assoc-ref inputs "liby"))
>         (out (assoc-ref outputs "out")))
>     ...))

That looks actually quite useful to me.

The general drawback of such syntax rules is that newcomers do not see all
the inner cogwheels of the system. So on one hand, one gains that contributing
packages becomes easier; on the other hand, understanding what is actually
happening becomes harder, and also learning scheme through guix becomes more
difficult as we move to our own domain specific language.

Andreas

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Some macros to make package definitions prettier
  2015-02-25 17:06   ` Thompson, David
@ 2015-02-25 19:27     ` Taylan Ulrich Bayırlı/Kammer
  0 siblings, 0 replies; 16+ messages in thread
From: Taylan Ulrich Bayırlı/Kammer @ 2015-02-25 19:27 UTC (permalink / raw)
  To: Thompson, David; +Cc: guix-devel

"Thompson, David" <dthompson2@worcester.edu> writes:

> On Wed, Feb 25, 2015 at 12:04 PM, Thompson, David
> <dthompson2@worcester.edu> wrote:
>
>> I understand the temptation to name it 'modify-phases', but since this
>> macro applies to any alist, I think 'modify-alist' or something with
>> "alist" in the name would be more appropriate.
>
> Looking again, I see that the above isn't quite true.  The
> 'modify-phases' macro assumes that the keys of the alist are symbols
> so that the user doesn't have to quote the phase names.
>
> - Dave

Right.  I was going to mention that, then forgot.

If we ever need a generic `alist-modify', we can do that too, but for
now this seems to be the only(?) use-case, and I think it's a big step
towards allowing non-Schemers to work with package definitions without
intimidation by foreign concepts and terminology.  (As simple as alists
are once one grasps them, it will be one more little annoyance for those
who aren't motivated to learn Scheme.)

Taylan

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Some macros to make package definitions prettier
  2015-02-25 18:12 ` Andreas Enge
@ 2015-02-25 19:46   ` Taylan Ulrich Bayırlı/Kammer
  2015-02-25 20:24   ` Thompson, David
  1 sibling, 0 replies; 16+ messages in thread
From: Taylan Ulrich Bayırlı/Kammer @ 2015-02-25 19:46 UTC (permalink / raw)
  To: Andreas Enge; +Cc: guix-devel

Andreas Enge <andreas@enge.fr> writes:

> Actually, I do not like the imperative, non-functional style of these
> syntax rules. For me, they rather obscure what is happening.

For those not very familiar with Scheme, the sequential notation will be
significantly more readable.  For those familiar with Scheme, it should
be trivial to learn.  Wouldn't you say it's worth it in the long run?

And just to chip in my personal opinion, I find the deeply nested and
reverse notation to be fairly ugly. :-) The notation I propose builds on
the idea of a pipeline, which is still purely functional, and I suspect
it's more intuitive to most humans even if they know FP well.

> The general drawback of such syntax rules is that newcomers do not see
> all the inner cogwheels of the system. So on one hand, one gains that
> contributing packages becomes easier; on the other hand, understanding
> what is actually happening becomes harder, and also learning scheme
> through guix becomes more difficult as we move to our own domain
> specific language.

Indeed, I agree.  However, I think these are simple enough macros, such
that if the manual just shows with an example what their use expands to,
it should be enough for those interested to quickly grasp it.

Taylan

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Some macros to make package definitions prettier
  2015-02-25 18:12 ` Andreas Enge
  2015-02-25 19:46   ` Taylan Ulrich Bayırlı/Kammer
@ 2015-02-25 20:24   ` Thompson, David
  1 sibling, 0 replies; 16+ messages in thread
From: Thompson, David @ 2015-02-25 20:24 UTC (permalink / raw)
  To: Andreas Enge; +Cc: guix-devel

On Wed, Feb 25, 2015 at 1:12 PM, Andreas Enge <andreas@enge.fr> wrote:
>
> On Wed, Feb 25, 2015 at 05:42:23PM +0100, Taylan Ulrich Bayırlı/Kammer wrote:
>>   (delete foo)
>>   (replace bar 'x)
>>   (add-before baz pre-baz 'y)) ;=> ((bar . x) (pre-baz . y) (baz . 2))
>> This has the following advantages:
>> - The order in which the phases are modified is top-down, where in our
>>   current style it's bottom-up which both distracts (IMO), and one may
>>   forget, as the chain grows and one forgets that it's indeed just a
>>   chain of function calls like (foo (bar (baz x))).
>> - Indentation doesn't keep growing as one adds more modifications.
>
> Actually, I do not like the imperative, non-functional style of these
> syntax rules. For me, they rather obscure what is happening.

It's still functional.  Should we not use 'cond' because it obscures
the series of nested 'if' expressions that it truly is?

> The indentation is just a question of style; in my first recipes, I did not
> indent consecutive modifications of phases, which was just as readable,
> I think (but this only works if you indent manually, and people disliked
> the unorthodox (non-)indentation).

Yeah, I'm not too into manual indenting to make a nested form look linear.

> The general drawback of such syntax rules is that newcomers do not see all
> the inner cogwheels of the system. So on one hand, one gains that contributing
> packages becomes easier; on the other hand, understanding what is actually
> happening becomes harder, and also learning scheme through guix becomes more
> difficult as we move to our own domain specific language.

It's a balancing act.  We can certainly go overboard with macros.
However, I think it's important to build up our packaging language to
be more expressive and declarative.  So, a macro to hide the nested
alist consing that we do constantly is appealing to me.

My 2 cents,

- Dave

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Some macros to make package definitions prettier
  2015-02-25 17:04 ` Thompson, David
  2015-02-25 17:06   ` Thompson, David
@ 2015-02-25 20:54   ` Taylan Ulrich Bayırlı/Kammer
  1 sibling, 0 replies; 16+ messages in thread
From: Taylan Ulrich Bayırlı/Kammer @ 2015-02-25 20:54 UTC (permalink / raw)
  To: Thompson, David; +Cc: guix-devel

"Thompson, David" <dthompson2@worcester.edu> writes:

>> (phase-lambda ((inputs (libx liby))
>>                (outputs (out)))
>>   ...)
>>
>> ;;; effectively equivalent to:
>>
>> (lambda* (#:key inputs outputs #:allow-other-keys)
>>   (let ((libx (assoc-ref inputs "libx"))
>>         (liby (assoc-ref inputs "liby"))
>>         (out (assoc-ref outputs "out")))
>>     ...))
>
> I'm not sure I like combining the alist destructuring part of this
> macro.  IMO, 'phase-lambda' could just take care of the 'lambda*'
> boilerplate, and maybe another macro ('alist-let'?) to reduce the
> 'assoc-ref' usage.

So we have

(phase-lambda ((inputs (libx liby))
               (outputs (out)))
  body)

vs. something like

(phase-lambda (inputs outputs)
  (alist-let ((inputs (libx liby))
              (outputs (out)))
    body))

which consists of two parts which are principally orthogonal.

I suspect that the above combination will be the overwhelming majority
of both these macros' use-cases if we split them, meaning we will have
done something impractical for the sake of a principle.

In fact the above implied definition of `alist-let' is still contrived
for this special case; if I really implemented a stand-alone
`alist-let', I would probably not make it support multiple clauses like
that, meaning the code would look something like:

(phase-lambda (inputs outputs)
  (alist-let inputs (libx lib)
    (alist-let outputs (out)
      body)))

which is unpleasant.

Others who have more experience with the larger codebase of Guix (or
even just Scheme codebases in general) should tell me whether my attempt
at pragmatism and the "You Ain't Gonna Need It" mentality is mistaken
here, but I think the `phase-lambda' that subsumes `alist-let' is the
best choice because that will cover our actual use-cases the best.

Taylan

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Some macros to make package definitions prettier
  2015-02-25 16:42 Some macros to make package definitions prettier Taylan Ulrich Bayırlı/Kammer
  2015-02-25 17:04 ` Thompson, David
  2015-02-25 18:12 ` Andreas Enge
@ 2015-02-25 23:32 ` Ludovic Courtès
  2015-02-26 11:07   ` Taylan Ulrich Bayırlı/Kammer
  2 siblings, 1 reply; 16+ messages in thread
From: Ludovic Courtès @ 2015-02-25 23:32 UTC (permalink / raw)
  To: Taylan Ulrich "Bayırlı/Kammer"; +Cc: guix-devel

taylanbayirli@gmail.com (Taylan Ulrich "Bayırlı/Kammer") skribis:

> (modify-phases '((foo . 0) (bar . 1) (baz . 2))
>   (delete foo)
>   (replace bar 'x)
>   (add-before baz pre-baz 'y)) ;=> ((bar . x) (pre-baz . y) (baz . 2))

I like it!  Let’s put it in (guix utils)?

> ;;; phase-lambda
>
> (define-syntax phase-lambda
>   (syntax-rules ()
>     ((phase-lambda ((arg (alist-entry ...))
>                     ...)
>        body ...)
>      (lambda* (#:key arg ... #:allow-other-keys)
>        (let-values (((alist-entry ...)
>                      (let ((arg* arg))
>                        (values
>                         (assoc-ref arg* (symbol->string 'alist-entry))
>                         ...)))
>                     ...)
>          body ...)))))
>
> ;;; Usage example:
>
> (phase-lambda ((inputs (libx liby))
>                (outputs (out)))
>   ...)
>
> ;;; effectively equivalent to:
>
> (lambda* (#:key inputs outputs #:allow-other-keys)
>   (let ((libx (assoc-ref inputs "libx"))
>         (liby (assoc-ref inputs "liby"))
>         (out (assoc-ref outputs "out")))
>     ...))
>
>
> This saves the usual boilerplate of '(#:key inputs outputs
> #:allow-other-keys)' and the subsequent `assoc-ref' uses.

Clearly, this is something we must address.  However, I’m uneasy with
this solutions for two reasons:

  1. The embedded ‘symbol->string’, and the fact that the developer no
     longer types in "foo" when the ‘inputs’ field has "foo" (as a
     string), making the connection non-obvious.

  2. In the grand scheme of things, gexps make the problem moot:

     (lambda _
       (frob-libs #$libx #$liby:include)
       (stuff-output #$output)
       ...)

However, there’s a complication: currently we can change the ‘inputs’
field of a package (like ‘package-with-explicit-inputs’ etc. do), and
its build script will get to see the new inputs, which is super
convenient.

Conversely, gexps currently end up hard-coding the output file name of
the package directly in the build script, which prevents this kind of
“input rewriting.”

I don’t yet have a nice idea on how to solve that, but that’s an
important thing to do.

WDYT?

Thank you,
Ludo’.

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Some macros to make package definitions prettier
  2015-02-25 23:32 ` Ludovic Courtès
@ 2015-02-26 11:07   ` Taylan Ulrich Bayırlı/Kammer
  2015-02-26 21:39     ` Ludovic Courtès
  2015-02-26 21:41     ` Ludovic Courtès
  0 siblings, 2 replies; 16+ messages in thread
From: Taylan Ulrich Bayırlı/Kammer @ 2015-02-26 11:07 UTC (permalink / raw)
  To: Ludovic Courtès; +Cc: guix-devel

[-- Attachment #1: Type: text/plain, Size: 397 bytes --]

ludo@gnu.org (Ludovic Courtès) writes:

> taylanbayirli@gmail.com (Taylan Ulrich "Bayırlı/Kammer") skribis:
>
>> (modify-phases '((foo . 0) (bar . 1) (baz . 2))
>>   (delete foo)
>>   (replace bar 'x)
>>   (add-before baz pre-baz 'y)) ;=> ((bar . x) (pre-baz . y) (baz . 2))
>
> I like it!  Let’s put it in (guix utils)?

Shouldn't it go to (guix build utils)?  Here's a patch:


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: patch --]
[-- Type: text/x-diff, Size: 2117 bytes --]

From 320a974e9b04959544bb93c67766957541ec02ad Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Taylan=20Ulrich=20Bay=C4=B1rl=C4=B1/Kammer?=
 <taylanbayirli@gmail.com>
Date: Thu, 26 Feb 2015 11:51:11 +0100
Subject: [PATCH] utils: Add 'modify-phases'.

* guix/build/utils.scm (modify-phases): New macro.
---
 guix/build/utils.scm | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/guix/build/utils.scm b/guix/build/utils.scm
index 4407f9a..c35966f 100644
--- a/guix/build/utils.scm
+++ b/guix/build/utils.scm
@@ -54,6 +54,7 @@
             alist-cons-before
             alist-cons-after
             alist-replace
+            modify-phases
             with-atomic-file-replacement
             substitute
             substitute*
@@ -423,6 +424,33 @@ An error is raised when no such pair exists."
       ((_ after ...)
        (append before (alist-cons key value after))))))
 
+(define-syntax-rule (modify-phases phases mod-spec ...)
+  "Modify PHASES sequentially as per each MOD-SPEC, which may have one of the
+following forms:
+
+  (delete <old-phase-name>)
+  (replace <old-phase-name> <new-phase>)
+  (add-before <old-phase-name> <new-phase-name> <new-phase>)
+  (add-after <old-phase-name> <new-phase-name> <new-phase>)
+
+Where every <*-phase-name> is an automatically quoted symbol, and <new-phase>
+an expression evaluating to a procedure."
+  (let* ((phases* phases)
+         (phases* (%modify-phases phases* mod-spec))
+         ...)
+    phases*))
+
+(define-syntax %modify-phases
+  (syntax-rules (delete replace add-before add-after)
+    ((_ phases (delete old-phase-name))
+     (alist-delete 'old-phase-name phases))
+    ((_ phases (replace old-phase-name new-phase))
+     (alist-replace 'old-phase-name new-phase phases))
+    ((_ phases (add-before old-phase-name new-phase-name new-phase))
+     (alist-cons-before 'old-phase-name 'new-phase-name new-phase phases))
+    ((_ phases (add-after old-phase-name new-phase-name new-phase))
+     (alist-cons-after 'old-phase-name 'new-phase-name new-phase phases))))
+
 \f
 ;;;
 ;;; Text substitution (aka. sed).
-- 
2.2.1


[-- Attachment #3: Type: text/plain, Size: 97 bytes --]


On the other topic, I'm afraid I know yet too little about gexprs and
Guix internals...

Taylan

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* Re: Some macros to make package definitions prettier
  2015-02-26 11:07   ` Taylan Ulrich Bayırlı/Kammer
@ 2015-02-26 21:39     ` Ludovic Courtès
  2015-03-03 16:49       ` Taylan Ulrich Bayırlı/Kammer
  2015-02-26 21:41     ` Ludovic Courtès
  1 sibling, 1 reply; 16+ messages in thread
From: Ludovic Courtès @ 2015-02-26 21:39 UTC (permalink / raw)
  To: Taylan Ulrich "Bayırlı/Kammer"; +Cc: guix-devel

taylanbayirli@gmail.com (Taylan Ulrich "Bayırlı/Kammer") skribis:

> ludo@gnu.org (Ludovic Courtès) writes:
>
>> taylanbayirli@gmail.com (Taylan Ulrich "Bayırlı/Kammer") skribis:
>>
>>> (modify-phases '((foo . 0) (bar . 1) (baz . 2))
>>>   (delete foo)
>>>   (replace bar 'x)
>>>   (add-before baz pre-baz 'y)) ;=> ((bar . x) (pre-baz . y) (baz . 2))
>>
>> I like it!  Let’s put it in (guix utils)?
>
> Shouldn't it go to (guix build utils)?  Here's a patch:

Right.  I’ve applied it locally and will push shortly.

Ludo’.

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Some macros to make package definitions prettier
  2015-02-26 11:07   ` Taylan Ulrich Bayırlı/Kammer
  2015-02-26 21:39     ` Ludovic Courtès
@ 2015-02-26 21:41     ` Ludovic Courtès
  1 sibling, 0 replies; 16+ messages in thread
From: Ludovic Courtès @ 2015-02-26 21:41 UTC (permalink / raw)
  To: Taylan Ulrich "Bayırlı/Kammer"; +Cc: guix-devel

BTW, this is one of this situation where we’d like to have a tool to
apply sexp-patches, so we can convert everything to use ‘modify-phases’
in one go.

Perhaps <https://github.com/rmculpepper/sexp-rewrite> would work for
that?

Ludo’.

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Some macros to make package definitions prettier
  2015-02-26 21:39     ` Ludovic Courtès
@ 2015-03-03 16:49       ` Taylan Ulrich Bayırlı/Kammer
  2015-03-03 20:44         ` Ludovic Courtès
  0 siblings, 1 reply; 16+ messages in thread
From: Taylan Ulrich Bayırlı/Kammer @ 2015-03-03 16:49 UTC (permalink / raw)
  To: Ludovic Courtès; +Cc: guix-devel

ludo@gnu.org (Ludovic Courtès) writes:

> I’ve applied it locally and will push shortly.

It might be too late, but I have a nitpick on my macro: the implicit
quoting of phase names 1. makes it impossible to provide them
dynamically (e.g. procedure argument), 2. might give an illusion that
they're sort of compile-time constants (like the 'delete', 'add-before',
etc. tokens are).

I guess it's fine since they are literal symbols in pretty much all
cases (or really all cases) so far, but it bothered me so I wanted to
share; it might be best to avoid such implicit-quoting in the future.


Another nitpick would be that standards-compliant syntax-rules won't
match the 'delete', 'replace', etc. literal tokens if they have a
different binding during use than during definition of the macro.  (The
identifier is matched by symbol name (i.e. "unhygienically") only if
it's unbound during both definition and use.)  But I think this is
really a problem in the Scheme standard, because this kind of macro is
probably ubiquitous in Scheme code "in the wild."  (And psyntax usually
does it the way we expect.)


Regarding the automatic conversion, I'll look into your recommendation,
and also ponder on a hand-baked solution in Guile or Elisp, but I wonder
if it will be possible to cover all edge-cases, especially comments.  On
the upside, we can auto-verify the results (sans comments and code
formatting) by comparing package objects for equality before and after
the transformation, since a use of 'modify-phases' should have the exact
same result as the direct alist mangling...

Taylan

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Some macros to make package definitions prettier
  2015-03-03 16:49       ` Taylan Ulrich Bayırlı/Kammer
@ 2015-03-03 20:44         ` Ludovic Courtès
  2015-03-03 22:47           ` Taylan Ulrich Bayırlı/Kammer
  0 siblings, 1 reply; 16+ messages in thread
From: Ludovic Courtès @ 2015-03-03 20:44 UTC (permalink / raw)
  To: Taylan Ulrich "Bayırlı/Kammer"; +Cc: guix-devel

taylanbayirli@gmail.com (Taylan Ulrich "Bayırlı/Kammer") skribis:

> ludo@gnu.org (Ludovic Courtès) writes:
>
>> I’ve applied it locally and will push shortly.
>
> It might be too late, but I have a nitpick on my macro: the implicit
> quoting of phase names 1. makes it impossible to provide them
> dynamically (e.g. procedure argument), 2. might give an illusion that
> they're sort of compile-time constants (like the 'delete', 'add-before',
> etc. tokens are).
>
> I guess it's fine since they are literal symbols in pretty much all
> cases (or really all cases) so far, but it bothered me so I wanted to
> share; it might be best to avoid such implicit-quoting in the future.

I actually agree.  Well, next round?

> Another nitpick would be that standards-compliant syntax-rules won't
> match the 'delete', 'replace', etc. literal tokens if they have a
> different binding during use than during definition of the macro.  (The
> identifier is matched by symbol name (i.e. "unhygienically") only if
> it's unbound during both definition and use.)  But I think this is
> really a problem in the Scheme standard, because this kind of macro is
> probably ubiquitous in Scheme code "in the wild."  (And psyntax usually
> does it the way we expect.)

In think Guile 2.1 is standards-compliant in that respect though.  A
related problem will be the ‘_’ procedure of (guix ui) that will need to
be renamed (which is annoying at worst, but OK.)  ‘delete’ might be more
of a problem.

> Regarding the automatic conversion, I'll look into your recommendation,
> and also ponder on a hand-baked solution in Guile or Elisp, but I wonder
> if it will be possible to cover all edge-cases, especially comments.  On
> the upside, we can auto-verify the results (sans comments and code
> formatting) by comparing package objects for equality before and after
> the transformation, since a use of 'modify-phases' should have the exact
> same result as the direct alist mangling...

Yes, but the package object contains quoted code, so we can’t directly
compare them for equality in this case.

That said, any problems would be easily spotted I guess.

Thanks,
Ludo’.

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Some macros to make package definitions prettier
  2015-03-03 20:44         ` Ludovic Courtès
@ 2015-03-03 22:47           ` Taylan Ulrich Bayırlı/Kammer
  2015-03-04  9:52             ` Ludovic Courtès
  0 siblings, 1 reply; 16+ messages in thread
From: Taylan Ulrich Bayırlı/Kammer @ 2015-03-03 22:47 UTC (permalink / raw)
  To: Ludovic Courtès; +Cc: guix-devel

ludo@gnu.org (Ludovic Courtès) writes:

> I actually agree.  Well, next round?

If you want. :-) I thought it might be too much to have a second commit
that touches all recipes where 'modify-phases' is used, but maybe I'm
being too pedantic.

> In think Guile 2.1 is standards-compliant in that respect though.  A
> related problem will be the ‘_’ procedure of (guix ui) that will need
> to be renamed (which is annoying at worst, but OK.)  ‘delete’ might be
> more of a problem.

Hm, if Guile 2.1 intends to have a fully hygienic syntax-rules by
default, I would expect it to offer a way to enable the alternative
behavior for a given syntax-rules usage, because AFAIK it's quite common
(if not more common) that unhygienic matching is desired.

Otherwise, we could just use slightly different identifiers:
phase-delete, phase-replace, phase-add-before, phase-add-after.

> Yes, but the package object contains quoted code, so we can’t directly
> compare them for equality in this case.

Ah, I didn't think of that.

Taylan

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Some macros to make package definitions prettier
  2015-03-03 22:47           ` Taylan Ulrich Bayırlı/Kammer
@ 2015-03-04  9:52             ` Ludovic Courtès
  0 siblings, 0 replies; 16+ messages in thread
From: Ludovic Courtès @ 2015-03-04  9:52 UTC (permalink / raw)
  To: Taylan Ulrich "Bayırlı/Kammer"; +Cc: guix-devel

taylanbayirli@gmail.com (Taylan Ulrich "Bayırlı/Kammer") skribis:

> ludo@gnu.org (Ludovic Courtès) writes:
>
>> I actually agree.  Well, next round?
>
> If you want. :-) I thought it might be too much to have a second commit
> that touches all recipes where 'modify-phases' is used, but maybe I'm
> being too pedantic.

Currently ‘modify-phases’ is only used in build systems, so it’s not too
late.

>> In think Guile 2.1 is standards-compliant in that respect though.  A
>> related problem will be the ‘_’ procedure of (guix ui) that will need
>> to be renamed (which is annoying at worst, but OK.)  ‘delete’ might be
>> more of a problem.
>
> Hm, if Guile 2.1 intends to have a fully hygienic syntax-rules by
> default, I would expect it to offer a way to enable the alternative
> behavior for a given syntax-rules usage, because AFAIK it's quite common
> (if not more common) that unhygienic matching is desired.

Yeah I have mixed feelings about it.

> Otherwise, we could just use slightly different identifiers:
> phase-delete, phase-replace, phase-add-before, phase-add-after.

This is an example of an undesirable side effect.  :-)

Ludo’.

^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2015-03-04  9:53 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-02-25 16:42 Some macros to make package definitions prettier Taylan Ulrich Bayırlı/Kammer
2015-02-25 17:04 ` Thompson, David
2015-02-25 17:06   ` Thompson, David
2015-02-25 19:27     ` Taylan Ulrich Bayırlı/Kammer
2015-02-25 20:54   ` Taylan Ulrich Bayırlı/Kammer
2015-02-25 18:12 ` Andreas Enge
2015-02-25 19:46   ` Taylan Ulrich Bayırlı/Kammer
2015-02-25 20:24   ` Thompson, David
2015-02-25 23:32 ` Ludovic Courtès
2015-02-26 11:07   ` Taylan Ulrich Bayırlı/Kammer
2015-02-26 21:39     ` Ludovic Courtès
2015-03-03 16:49       ` Taylan Ulrich Bayırlı/Kammer
2015-03-03 20:44         ` Ludovic Courtès
2015-03-03 22:47           ` Taylan Ulrich Bayırlı/Kammer
2015-03-04  9:52             ` Ludovic Courtès
2015-02-26 21:41     ` Ludovic Courtès

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/guix.git

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).