guix-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Some macros to make package definitions prettier


From: Thompson, David
Subject: Re: Some macros to make package definitions prettier
Date: Wed, 25 Feb 2015 12:04:31 -0500

On Wed, Feb 25, 2015 at 11:42 AM, Taylan Ulrich Bayırlı/Kammer
<address@hidden> 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!



reply via email to

[Prev in Thread] Current Thread [Next in Thread]