The procedures that operate on the store described in the previous sections all take an open connection to the build daemon as their first argument. Although the underlying model is functional, they either have side effects or depend on the current state of the store.
The former is inconvenient: the connection to the build daemon has to be carried around in all those functions, making it impossible to compose functions that do not take that parameter with functions that do. The latter can be problematic: since store operations have side effects and/or depend on external state, they have to be properly sequenced.
This is where the
(guix monads) module comes in. This module
provides a framework for working with monads, and a particularly
useful monad for our uses, the store monad. Monads are a
construct that allows two things: associating “context” with values
(in our case, the context is the store), and building sequences of
computations (here computations includes accesses to the store.) Values
in a monad—values that carry this additional context—are called
monadic values; procedures that return such values are called
Consider this “normal” procedure:
(define (profile.sh store) ;; Return the name of a shell script in the store that ;; initializes the 'PATH' environment variable. (let* ((drv (package-derivation store coreutils)) (out (derivation->output-path drv))) (add-text-to-store store "profile.sh" (format #f "export PATH=~a/bin" out))))
(guix monads), it may be rewritten as a monadic function:
(define (profile.sh) ;; Same, but return a monadic value. (mlet %store-monad ((bin (package-file coreutils "bin"))) (text-file "profile.sh" (string-append "export PATH=" bin))))
There are two things to note in the second version: the
parameter is now implicit, and the monadic value returned by
package-file—a wrapper around
derivation->output-path—is bound using
instead of plain
Calling the monadic
profile.sh has no effect. To get the desired
effect, one must use
(run-with-store (open-connection) (profile.sh)) ⇒ /nix/store/...-profile.sh
The main syntactic forms to deal with monads in general are described below.
return forms in body as being
Return a monadic value that encapsulates val.
Bind monadic value mval, passing its “contents” to monadic procedure mproc6.
Bind the variables var to the monadic values mval in
body. The form (var -> val) binds var to the
“normal” value val, as per
mlet* is to
let* is to
(see Local Bindings in GNU Guile Reference Manual).
The interface to the store monad provided by
(guix monads) is as
The store monad. Values in the store monad encapsulate accesses to the
store. When its effect is needed, a value of the store monad must be
“evaluated” by passing it to the
run-with-store procedure (see
Run mval, a monadic value in the store monad, in store, an open store connection.
Return as a monadic value the absolute file name in the store of the file containing text.
value in the absolute file name of file within the output directory of package. When file is omitted, return the name of the output directory of package.
Monadic version of
Monadic version of
package-derivation (see Defining Packages).
This operation is commonly referred to as “bind”, but that name denotes an unrelated procedure in Guile. Thus we use this somewhat cryptic symbol inherited from the Haskell language.