[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Some macros to make package definitions prettier
From: |
Taylan Ulrich Bayırlı/Kammer |
Subject: |
Some macros to make package definitions prettier |
Date: |
Wed, 25 Feb 2015 17:42:23 +0100 |
User-agent: |
Gnus/5.13 (Gnus v5.13) Emacs/24.4 (gnu/linux) |
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
- Some macros to make package definitions prettier,
Taylan Ulrich Bayırlı/Kammer <=