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

Reply via email to