unofficial mirror of help-guix@gnu.org 
 help / color / mirror / Atom feed
* When and how should one use "(thunked)" from (guix records)?
@ 2021-10-19  8:38 Joshua Branson
  0 siblings, 0 replies; only message in thread
From: Joshua Branson @ 2021-10-19  8:38 UTC (permalink / raw)
  To: help-guix

Hey guix!  I'm trying to flush out the (guix records) for the
=opensmtpd-service=.  It's super fun doing it by the way.  If you've
never messed with (guix records) then you should totally give it a
try.  Thanks for the author of (guix records).  You did a really great
job!  The purpose of this email is to get some suggestions on my
opensmtpd-records.scm file and to use this email as a VERY ROUGH draft
for a (guix records) blog post, if there is interest in it.  :)

The code that I have so far can be seen here:

https://notabug.org/jbranso/linode-guix-system-configuration/src/master/opensmtpd-records.scm

I'm open to suggestions.  :)

I have a basic procedure that turns a <opensmtpd-configuration> into a string...

(define (opensmtpd-configuration->string record)
   ...)

I've had a ton of fun using the =(thunked)= bit in records.  The
documentation in the source code says something like this (also does
the guix manual document guix records somewhere?).

#+BEGIN_EXAMPLE
The 'port' field is \"thunked\", meaning that calls like '(thing-port x)' will
actually compute the field's value in the current dynamic extent, which is
useful when referring to fluids in a field's value.  Furthermore, that thunk
can access the record it belongs to via the 'this-thing' identifier.
#+END_EXAMPLE

I've found some "too-clever" ways of using (thunked) that people on
irc mentioned may NOT be wise to use.  For example, using (thunked) to
define mutually exclusive fieldnames and a fieldname that returns
another fieldnames value.  I think these are not "good" ways of using
(thunked).  Anyone have any good ideas for using (thunked)?

Below is some obligatory code.

* This bit of guix records shows off the =(thunked)= and =this-record=.
=(thunked)= lets you refer to the record that is being defined.  In
this case, I am defining mutually exclusive fieldnames...If =relay= is
defined, then =local-delivery= returns =#f= as its value, which is
pretty awesome.

*Note*: a simpler way to define a mutually exclusive fieldnames is to
have one fieldname that accepts =<cat-record>= or =<dog-record>=.  

#+BEGIN_SRC scheme
    (define-record-type* <opensmtpd-action>
      opensmtpd-action make-opensmtpd-action
      opensmtpd-action?
      this-record
      (name opensmtpd-action-name
            (default "local"))
      (relay opensmtpd-action-relay
             (default "#f")
      (local-delivery opensmtpd-action-local-delivery ;;type <opensmtpd-local-delivery-configuration>
                      ;; local-delivery has a default value so (service opensmtpd-service) will just work for
                      ;; local email delivery
                      (default (opensmtpd-local-delivery-configuration))
                      (thunked)
                      (sanitize (lambda (value)
                                  (cond
                                   ;; if relay has a value, then local-delivery should be #f
                                   ;; man (guix records) rocks!
                                   ;; TODO/FIXME, perhaps I should merge fieldnames 'relay', 'local-delivery', 'forward-only',
                                   ;; and 'expand-only' into one fildname called "method".  Then the user has to use a specific
                                   ;; record type to be mutually exclusive.
                                   [(opensmtpd-action-relay this-record)
                                       #f] 
                                   [(opensmtpd-local-delivery-configuration? value)
                                       value] 
                                   [else
                                    (display (string-append "<opensmtpd-action> fieldname 'local-delivery' "
                                                            "needs to be of type <opensmtpd-local-delivery-configuration>.\n"))
                                    (throw 'bad! value)])))))
#+END_SRC

* This bit of guix records defines a fieldname which returns the type of another fieldname

Fieldname =type= returns the type of values that =values= has either
='list-of-strings= or ='assoc-list=.

*Note*: It is probably better to define a function outside of the
record that returns the type that value is.  That just makes it
conceptually easier for the next hacker.

#+BEGIN_SRC scheme
  (define-record-type* <opensmtpd-table>
    opensmtpd-table make-opensmtpd-table
    opensmtpd-table?
    this-record
    ;; string
    ;; is a list of values or key values
    ;; eg: (list "mysite.me" "your-site.com")
    ;; eg: (list ("joshua" . "joshua@gnu.org") ("james" . "james@gnu.org"))
    (values opensmtpd-table-values
            (default #f)
            (sanitize (lambda (value)
                        (if (or (list-of-strings? value)
                                (assoc-list? value))
                            value
                            (begin
                              (display "<opensmtpd-table> fieldname: 'value' must be a list of strings or an association list.\n")
                              (throw 'bad! value))))))
    ;; can be of type: (quote list-of-strings) or (quote assoc-list)
    ;; type is discovered during the initialition phase.  The user SHOULD NEVER set the type.
    ;; TODO jpoiret: on irc reccomends that I just use an outside function to determine fieldname 'values', type.
    ;; it would be "simpler" and possibly easier for the next person working on this code to understand what is happening.
    (type opensmtpd-table-type
          (default #f)
          (thunked)
          (sanitize (lambda (value)
                      (if (list-of-strings? (opensmtpd-table-values this-record))
                          (quote list-of-strings)
                          (quote assoc-list))))))
#+END_SRC

* I found this is the guix source code...I'm not sure what the (thunked) offers...
#+BEGIN_SRC scheme
;; Configuration of an Xorg server.
(define-record-type* <xorg-configuration>
  xorg-configuration make-xorg-configuration
  xorg-configuration?
  (modules          xorg-configuration-modules    ;list of packages
                    (thunked)
                    ; filter out modules not supported on current system
                    (default (filter
                              (lambda (p)
                                (member (%current-system)
                                        (package-supported-systems p)))
                              %default-xorg-modules)))
  (fonts            xorg-configuration-fonts      ;list of packges
                    (default %default-xorg-fonts))
  (drivers          xorg-configuration-drivers    ;list of strings
                    (default '()))
  (resolutions      xorg-configuration-resolutions ;list of tuples
                    (default '()))
  (keyboard-layout  xorg-configuration-keyboard-layout ;#f | <keyboard-layout>
                    (default #f))
  (extra-config     xorg-configuration-extra-config ;list of strings
                    (default '()))
  (server           xorg-configuration-server     ;package
                    (default xorg-server))
  (server-arguments xorg-configuration-server-arguments ;list of strings
                    (default %default-xorg-server-arguments)))

#+END_SRC



^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2021-10-19  8:38 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-10-19  8:38 When and how should one use "(thunked)" from (guix records)? Joshua Branson

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