diff mbox series

[bug#50614,core-updates] build: utils: Add ‘optional’ macro.

Message ID b7ee7798dbf384021126a2cd4366b604730181b8.1631776133.git.public@yoctocell.xyz
State New
Headers show
Series [bug#50614,core-updates] build: utils: Add ‘optional’ macro. | expand

Checks

Context Check Description
cbaines/applying patch fail View Laminar job
cbaines/issue success View issue

Commit Message

Xinglu Chen Sept. 16, 2021, 7:11 a.m. UTC
* guix/build/utils.scm (optional): New syntax
* tests/build-utils.scm ("optional: expr1 is non-#f", optional: expr1 is #f"):
  Test it.
* guix.texi (Build Utilities): Document it.
---
A common idiom I have seen is

  (if EXPR1
      EXPR2
      '())

with the ‘optional’ macro, one can just write

  (optional EXPR1
            EXPR2)

I am not sure if ‘optional’ is the best name (it was inspired by
‘lib.optional’ in Nixpkgs), feedback welcome!

 doc/guix.texi         | 35 +++++++++++++++++++++++++++++++++++
 guix/build/utils.scm  | 17 ++++++++++++++++-
 tests/build-utils.scm |  8 ++++++++
 3 files changed, 59 insertions(+), 1 deletion(-)


base-commit: 22f7d4bce1e694b7ac38e62410d76a6d46d96c5d

Comments

Liliana Marie Prikler Sept. 16, 2021, 4:21 p.m. UTC | #1
Hi,

Am Donnerstag, den 16.09.2021, 09:11 +0200 schrieb Xinglu Chen:
> * guix/build/utils.scm (optional): New syntax
> * tests/build-utils.scm ("optional: expr1 is non-#f", optional: expr1
> is #f"):
>   Test it.
> * guix.texi (Build Utilities): Document it.
> ---
> A common idiom I have seen is
> 
>   (if EXPR1
>       EXPR2
>       '())
> 
> with the ‘optional’ macro, one can just write
> 
>   (optional EXPR1
>             EXPR2)
> 
> I am not sure if ‘optional’ is the best name (it was inspired by
> ‘lib.optional’ in Nixpkgs), feedback welcome!
> 
>  doc/guix.texi         | 35 +++++++++++++++++++++++++++++++++++
>  guix/build/utils.scm  | 17 ++++++++++++++++-
>  tests/build-utils.scm |  8 ++++++++
>  3 files changed, 59 insertions(+), 1 deletion(-)
> 
> diff --git a/doc/guix.texi b/doc/guix.texi
> index 9a3e8ae12c..1bb9ddb397 100644
> --- a/doc/guix.texi
> +++ b/doc/guix.texi
> @@ -8801,6 +8801,41 @@ in a build phase of the @code{wireguard-tools} 
> package:
>          `("PATH" ":" prefix ,(list coreutils))))))
>  @end lisp
>  
> +@subsection Miscellaneous build utilities
> +
> +@cindex miscellaneous build utilities
> +This section documents some miscellaneous utilities that are useful
> to +have.
> +
> +@deffn {Scheme Syntax} optional @var{test} @var{consequent}
> +Like @code{when} (@pxref{Conditionals,,, guile, GNU Guile Reference
> +Manual}), but if @var{test} evaluates to false, return the empty
> list.
> +This is replaces the following idiom:
> +@end deffn
> +
> +@lisp
> +(if @var{test}
> +    @var{consequent}
> +    '())
> +@end lisp
> +
> +with this:
> +
> +@lisp
> +(optional @var{test}
> +          @var{consequent})
> +@end lisp          
> +
> +It can be useful when certain targets require an additional
> configure
> +flags, e.g.,
> +
> +@lisp
> +(arguments
> + `(#:configure-flags (list "--localstatedir=/var"
> +                           "--sysconfdir=/etc"
> +                           ,@@(optional (hurd-target?) '("--with-
> courage"))))
> +@end lisp
> +
>  @subsection Build Phases
>  
>  @cindex build phases
> diff --git a/guix/build/utils.scm b/guix/build/utils.scm
> index 3beb7da67a..ecf834461f 100644
> --- a/guix/build/utils.scm
> +++ b/guix/build/utils.scm
> @@ -8,6 +8,7 @@
>  ;;; Copyright © 2020 Efraim Flashner <efraim@flashner.co.il>
>  ;;; Copyright © 2020, 2021 Maxim Cournoyer <
> maxim.cournoyer@gmail.com>
>  ;;; Copyright © 2021 Maxime Devos <maximedevos@telenet.be>
> +;;; Copyright © 2021 Xinglu Chen <public@yoctocell.xyz>
>  ;;;
>  ;;; This file is part of GNU Guix.
>  ;;;
> @@ -123,7 +124,9 @@
>  
>              make-desktop-entry-file
>  
> -            locale-category->string))
> +            locale-category->string
> +
> +            optional))
>  
>  
>  ;;;
> @@ -1613,6 +1616,18 @@ returned."
>               LC_NAME LC_NUMERIC LC_PAPER LC_TELEPHONE
>               LC_TIME)))
>  
> +
> +;;;
> +;;; Misc.
> +;;;
> +
> +;; If EXPR1 evaluates to a non-#f value, return EXPR2.  Otherwise,
> return an
> +;; empty list.
> +(define-syntax optional
> +  (syntax-rules ()
> +    ((_ expr1 expr2)
> +     (if expr1 expr2 '()))))
> +
>  ;;; Local Variables:
>  ;;; eval: (put 'call-with-output-file/atomic 'scheme-indent-function 
> 1)
>  ;;; eval: (put 'call-with-ascii-input-file 'scheme-indent-function
> 1)
> diff --git a/tests/build-utils.scm b/tests/build-utils.scm
> index 6b131c0af8..44ad9bafc0 100644
> --- a/tests/build-utils.scm
> +++ b/tests/build-utils.scm
> @@ -3,6 +3,7 @@
>  ;;; Copyright © 2019 Ricardo Wurmus <rekado@elephly.net>
>  ;;; Copyright © 2021 Maxim Cournoyer <maxim.cournoyer@gmail.com>
>  ;;; Copyright © 2021 Maxime Devos <maximedevos@telenet.be>
> +;;; Copyright © 2021 Xinglu Chen <public@yoctocell.xyz>
>  ;;;
>  ;;; This file is part of GNU Guix.
>  ;;;
> @@ -287,5 +288,12 @@ print('hello world')"))
>            ("guile/bin" . ,(dirname (which "guile"))))
>          "guile"))))
>  
> +(test-equal "optional: expr1 is non-#f"
> +  'bar
> +  (optional 'foo 'bar))
> +
> +(test-equal "optional: expr1 is #f"
> +  '()
> +  (optional #f 'bar))
>  
>  (test-end)
> 
> base-commit: 22f7d4bce1e694b7ac38e62410d76a6d46d96c5d

Naming choice aside, I don't think I like the asymmetry behind having a
plain symbol on the one side vs. an empty list.  What about 
(list-if condition . rest), which evaluates to rest if condition is
true and otherwise nil?
Sarah Morgensen Sept. 17, 2021, 12:37 a.m. UTC | #2
Hi,

Xinglu Chen <public@yoctocell.xyz> writes:

> * guix/build/utils.scm (optional): New syntax
> * tests/build-utils.scm ("optional: expr1 is non-#f", optional: expr1 is #f"):
>   Test it.
> * guix.texi (Build Utilities): Document it.
> ---
> A common idiom I have seen is
>
>   (if EXPR1
>       EXPR2
>       '())
>
> with the ‘optional’ macro, one can just write
>
>   (optional EXPR1
>             EXPR2)
>
> I am not sure if ‘optional’ is the best name (it was inspired by
> ‘lib.optional’ in Nixpkgs), feedback welcome!

I like the idea!  But perhaps if we're getting rid of boilerplate, we
should go all the way and make it so that instead of

  (if EXPR1
      `(EXPR2 EXPR3)
      '())

we can write

  (optional EXPR1 EXPR2 EXPR3)

What do you think?

Also, maybe 'list-when' for the name?

> +@deffn {Scheme Syntax} optional @var{test} @var{consequent}
> +Like @code{when} (@pxref{Conditionals,,, guile, GNU Guile Reference
> +Manual}), but if @var{test} evaluates to false, return the empty list.
> +This is replaces the following idiom:
        ^ no "is"

> +@end deffn
> +
> +@lisp
> +(if @var{test}
> +    @var{consequent}
> +    '())
> +@end lisp
> +
> +with this:
> +
> +@lisp
> +(optional @var{test}
> +          @var{consequent})
> +@end lisp          
> +
> +It can be useful when certain targets require an additional configure
                                                 ^ no "an"

> +flags, e.g.,
> +
> +@lisp
> +(arguments
> + `(#:configure-flags (list "--localstatedir=/var"
> +                           "--sysconfdir=/etc"
> +                           ,@@(optional (hurd-target?) '("--with-courage"))))
                               ^ extra "@"?

--
Sarah
diff mbox series

Patch

diff --git a/doc/guix.texi b/doc/guix.texi
index 9a3e8ae12c..1bb9ddb397 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -8801,6 +8801,41 @@  in a build phase of the @code{wireguard-tools} package:
         `("PATH" ":" prefix ,(list coreutils))))))
 @end lisp
 
+@subsection Miscellaneous build utilities
+
+@cindex miscellaneous build utilities
+This section documents some miscellaneous utilities that are useful to
+have.
+
+@deffn {Scheme Syntax} optional @var{test} @var{consequent}
+Like @code{when} (@pxref{Conditionals,,, guile, GNU Guile Reference
+Manual}), but if @var{test} evaluates to false, return the empty list.
+This is replaces the following idiom:
+@end deffn
+
+@lisp
+(if @var{test}
+    @var{consequent}
+    '())
+@end lisp
+
+with this:
+
+@lisp
+(optional @var{test}
+          @var{consequent})
+@end lisp          
+
+It can be useful when certain targets require an additional configure
+flags, e.g.,
+
+@lisp
+(arguments
+ `(#:configure-flags (list "--localstatedir=/var"
+                           "--sysconfdir=/etc"
+                           ,@@(optional (hurd-target?) '("--with-courage"))))
+@end lisp
+
 @subsection Build Phases
 
 @cindex build phases
diff --git a/guix/build/utils.scm b/guix/build/utils.scm
index 3beb7da67a..ecf834461f 100644
--- a/guix/build/utils.scm
+++ b/guix/build/utils.scm
@@ -8,6 +8,7 @@ 
 ;;; Copyright © 2020 Efraim Flashner <efraim@flashner.co.il>
 ;;; Copyright © 2020, 2021 Maxim Cournoyer <maxim.cournoyer@gmail.com>
 ;;; Copyright © 2021 Maxime Devos <maximedevos@telenet.be>
+;;; Copyright © 2021 Xinglu Chen <public@yoctocell.xyz>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -123,7 +124,9 @@ 
 
             make-desktop-entry-file
 
-            locale-category->string))
+            locale-category->string
+
+            optional))
 
 
 ;;;
@@ -1613,6 +1616,18 @@  returned."
              LC_NAME LC_NUMERIC LC_PAPER LC_TELEPHONE
              LC_TIME)))
 
+
+;;;
+;;; Misc.
+;;;
+
+;; If EXPR1 evaluates to a non-#f value, return EXPR2.  Otherwise, return an
+;; empty list.
+(define-syntax optional
+  (syntax-rules ()
+    ((_ expr1 expr2)
+     (if expr1 expr2 '()))))
+
 ;;; Local Variables:
 ;;; eval: (put 'call-with-output-file/atomic 'scheme-indent-function 1)
 ;;; eval: (put 'call-with-ascii-input-file 'scheme-indent-function 1)
diff --git a/tests/build-utils.scm b/tests/build-utils.scm
index 6b131c0af8..44ad9bafc0 100644
--- a/tests/build-utils.scm
+++ b/tests/build-utils.scm
@@ -3,6 +3,7 @@ 
 ;;; Copyright © 2019 Ricardo Wurmus <rekado@elephly.net>
 ;;; Copyright © 2021 Maxim Cournoyer <maxim.cournoyer@gmail.com>
 ;;; Copyright © 2021 Maxime Devos <maximedevos@telenet.be>
+;;; Copyright © 2021 Xinglu Chen <public@yoctocell.xyz>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -287,5 +288,12 @@  print('hello world')"))
           ("guile/bin" . ,(dirname (which "guile"))))
         "guile"))))
 
+(test-equal "optional: expr1 is non-#f"
+  'bar
+  (optional 'foo 'bar))
+
+(test-equal "optional: expr1 is #f"
+  '()
+  (optional #f 'bar))
 
 (test-end)