Hi Ludovic, > FWIW, Guix uses an approach along these lines: the ‘bitlbee-service’ > function, for instance, returns a ‘service’ object as a monadic value > (see > <http://www.gnu.org/software/guix/manual/guix.html#Defining-Services> > for details.)
The way I understand the section on the store monad is that it's really a state monad with a view on the current store (they should really show the underlying types to make this easier to understand). That's not related to the way they define services, but rather just how the store itself is used. Nix has the store built into the language. Side effects happen to build store paths and, once built, they appear like regular immutable values within the language. It's convenient, but makes the assumption that build outputs depend solely on their inputs, which unfortunately, as we know, is not always true at this point. However, the way they define services seems indeed a lot better than what we currently have. In part they already have what I think we should have (functional services), but with no algebraic structure behind it other than the store monad. > Unlike in NixOS, the service implementation doesn’t have access to the > rest of the system configuration, which I think is a good thing, as > you note. Absolutely. Everything they depend on should be an argument. > What’s unsatisfying (and thus subject to change) is that > ‘operating-system’ objects (which are pure declarations) end up with > monadic values in their ‘services’ field. That makes it inconvenient > to, say, filter items from that list, or to tweak their configuration, > because one first needs to bind them. That said, it’s probably not a > problem for Nix, because every Nix function is really a function in > what we call the “store monad”. You could think of it that way, if you wanted. I prefer to think of what Nix does as the same magic that functional languages do with other resources like memory (alloc and GC). > In your example, what would ‘bitlbee’, ‘nginx’ etc. return exactly? > An attribute set describing the service? As a first approximation there would be a Service monoid, which would combine certain typical attributes about a service, including startup scripts, required bind-mounts, required system resources and if really necessary shutdown scripts (most programs should shutdown properly when the container goes down). Service : Mon Its identity idS would be the empty service, which you can think of as an empty group of processes with no mounts, no resources, etc. The Bitlbee service would be constructed through a regular function that takes the typical bitlbee options. Nothing special here: bitlbee : BitlbeeConf -> Service The nginx function is more interesting. It involves a second monoid, the monoid of web services (identity idW): WebService : Mon Then nginx is a monoid morphism, nginx : WebService -> Service that is a function with additional structure, in particular: nginx x ◇ nginx y ≡ nginx (x ◇ y) nginx idW ≡ idS The most important part is to get the equivalence `≡` relation right, i.e. when do we regard two services as equivalent? This requires a lot of careful thought, because services in the real world are messy and effectful. Example: 1. One nginx instance serves two websites x and y. 2. Load balancer scenario: Three nginx instances. One serves x, one serves y, the other redirects to the correct instance depending on the request. 3. Mapping identities: A hundred load-balanced nginx instances, one of them serving x, a second one serving y and all others serving nothing at all (returning 404 unconditionally). These three examples really describe the same service. One may be a more efficient implementation, but they should be equivalent with respect to `≡`, because they are indistinguishable from the outside other than in exceptional cases (case 3 is more likely to run out of memory than case 1). That enables us to use equational reasoning for correctness. It also enables us to apply automatic semantics-preserving optimisations. Example: The host may be serving two sites. At the same time a system monitoring daemon might generate health reports periodically that are also served via HTTP. Such a configuration might look like: nginxStatic "site1.host" "/var/www/site1" <> nginxStatic "site2.host" "/var/www/site2" <> systemHealth "health.host" A semantics-preserving optimistation (which is really not an optimistation, but the way web services are combined) would collapse all of that to a single instance of nginx and one entry in the crontab for the health reporter. I hope this gives a first impression of how everything would fit together. Greets, Ertugrul _______________________________________________ nix-dev mailing list nix-dev@lists.science.uu.nl http://lists.science.uu.nl/mailman/listinfo/nix-dev