Good morning Taylan, > First, let me point out a more conventional alternative to what your > 'decorate' macro does: > > (define (compose proc . rest) > "Functional composition; e.g. ((compose x y) a) = (x (y a))." > (if (null? rest) > proc > (let ((rest-proc (apply compose rest))) > (lambda x > (let-values ((x (apply rest-proc x))) > (apply proc x)))))) > > This allows for something like: > > ((compose install-foo install-bar install-zfs) > (operating-system ...)) > > Or perhaps cleaner: > > (define my-os-modifier (compose install-foo install-bar install-zfs)) > > (my-os-modifier > (operating-system ...)) > > If you need custom modifications within, you can do: > > (define my-os-modifier > (compose install-foo > (lambda (os) ...) > install-bar)) > > It's more verbose, but doesn't "break" standard Scheme syntax as much. > Function composition is conceptually pretty easy and probably more > well-known than "decorators" (which I had never heard of, personally).
Yes, except function composition does not work on syntactic forms, which is why, with `compose`, you have to separate the `operating-system` form instead of being able to compose `operating-system` with the rest of the os modifications. The intent is that you have already an existing `operating-system` form with a single layer of parenthesis. With `compose`, if you want to install ZFS and a bunch of other complex OS modifications, you have to add a layer of parenthesis. With `decorate`, you don't: ```scheme ((compose install-zfs install-foo) (operating-system (name "my-system") #;...)) ;vs (decorate (install-zfs install-foo operating-system) (nmae "my-system") #;...) ``` > > Fewer macros means the reader needs to keep fewer special rules in mind. Fine, I'm doubling down then. ```scheme (define-syntax compose-syntax (syntax-rules () ((compose-syntax (x ...)) (syntax-rules ::: () ((form args :::) (x ... args :::)))) ((compose-syntax x) (syntax-rules ::: () ((form args :::) (x args :::)))) ((compose-syntax (x ...) y ...) (syntax-rules ::: () ((form args :::) (let-syntax ((sub-syntax (compose-syntax y ...))) (x ... (sub-syntax args :::)))))) ((compose-syntax x y ...) (syntax-rules ::: () ((form args :::) (let-syntax ((sub-syntax (compose-syntax y ...)) (x (sub-syntax args :::))))))))) ``` Then use it as follows: ``` (define-syntax my-operating-system (compose-syntax (install-zfs #:options '(("zfs_arc_max" 5000000000)) #:os) operating-system)) (my-operating-system (name "my-system") #;...) ``` Again, the goal here is to keep the nestedness of your existing, very long `operating-system` form, which your simple `compose` function fails to do, because you can't compose syntax with `compose` and `operating-system` is a syntax form. > > Secondly, I wonder if passing an OS declaration through various > procedures that modify it is really the best approach in the first place. > > For build phases, we have the 'modify-phases' syntax. For services, > there is 'modify-services'. Maybe there should be a 'modify-os' kind of > syntax. (In other words, if we're going to invent new syntax, why not > go all-out and create the most convenient syntax for the use-case.) Because a *generic* form to modify the operating system is worthless --- you can just define the operating-system directly. What `install-zfs` does is that it installs the same kernel-specific package in three different points: * `kernel-loadable-modules`, because ZFS needs to get into the kernel somehow. * `packages`, because the kernel module is useless if you don't have the userland tools to interact with the kernel module. * `services`, because ZFS is well-documented outside of Guix as automatically mounting its filesystems at bootup, but that actually requires a bit of magic in the `init` system, specifically you need to actually **load** the module, then execute `zpool import -a -l` to have it scan for all filesystems and mount those that need automounting. Thus, an `install-zfs`, that is a *single* form that inserts the correct bits in the correct ***three*** places, makes the experience of adding ZFS to your `operating-system` easier because there's less scope for error in actually adding the package. You just add a single `install-zfs`, not add three things (plus an extra `(define my-zfs (make-zfs-package linux-libre-5.4))` before your form). Now, if this kind of simplifying form is useful for ZFS, I imagine that this kind of simplifying form would also exist for other things you could install into your operating system in the future. Thus, we need some way to take an existing `<operating-system>` and pass it through a number of single simplifying operating system transformations, which I don't think something like `modify-os` would work well with. Thanks raid5atemyhomework