Next: G-Expressions, Previous: Derivations, Up: Programming Interface [Contents][Index]

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 include 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
*monadic procedures*.

Consider this “normal” procedure:

(define (sh-symlink store) ;; Return a derivation that symlinks the 'bash' executable. (let* ((drv (package-derivation store bash)) (out (derivation->output-path drv)) (sh (string-append out "/bin/bash"))) (build-expression->derivation store "sh" `(symlink ,sh %output))))

Using `(guix monads)`

and `(guix gexp)`

, it may be rewritten
as a monadic function:

(define (sh-symlink) ;; Same, but return a monadic value. (mlet %store-monad ((drv (package->derivation bash))) (gexp->derivation "sh" #~(symlink (string-append #$drv "/bin/bash") #$output))))

There several things to note in the second version: the `store`

parameter is now implicit and is “threaded” in the calls to the
`package->derivation`

and `gexp->derivation`

monadic
procedures, and the monadic value returned by `package->derivation`

is *bound* using `mlet`

instead of plain `let`

.

As it turns out, the call to `package->derivation`

can even be
omitted since it will take place implicitly, as we will see later
(see G-Expressions):

(define (sh-symlink) (gexp->derivation "sh" #~(symlink (string-append #$bash "/bin/bash") #$output)))

Calling the monadic `sh-symlink`

has no effect. To get the desired
effect, one must use `run-with-store`

:

(run-with-store (open-connection) (sh-symlink)) ⇒ /gnu/store/...-sh-symlink

Note that the `(guix monad-repl)`

module extends Guile’s REPL with
new “meta-commands” to make it easier to deal with monadic procedures:
`run-in-store`

, and `enter-store-monad`

. The former, is used
to “run” a single monadic value through the store:

scheme@(guile-user)> ,run-in-store (package->derivation hello) $1 = #<derivation /gnu/store/…-hello-2.9.drv => …>

The latter enters a recursive REPL, where all the return values are automatically run through the store:

scheme@(guile-user)> ,enter-store-monad store-monad@(guile-user) [1]> (package->derivation hello) $2 = #<derivation /gnu/store/…-hello-2.9.drv => …> store-monad@(guile-user) [1]> (text-file "foo" "Hello!") $3 = "/gnu/store/…-foo" store-monad@(guile-user) [1]> ,q scheme@(guile-user)>

Note that non-monadic values cannot be returned in the
`store-monad`

REPL.

The main syntactic forms to deal with monads in general are provided by
the `(guix monads)`

module and are described below.

- Scheme Syntax:
**with-monad**`monad``body`... Evaluate any

`>>=`

or`return`

forms in`body`as being in`monad`.

- Scheme Syntax:
**return**`val` Return a monadic value that encapsulates

`val`.

- Scheme Syntax:
**>>=**`mval``mproc` *Bind*monadic value`mval`, passing its “contents” to monadic procedure`mproc`^{5}.

- Scheme Syntax:
**mlet**`monad`((`var``mval`) ...)`body`... - Scheme Syntax:
**mlet***`monad`((`var``mval`) ...)`body`... Bind the variables

`var`to the monadic values`mval`in`body`. The form (`var`->`val`) binds`var`to the “normal” value`val`, as per`let`

.`mlet*`

is to`mlet`

what`let*`

is to`let`

(see Local Bindings in GNU Guile Reference Manual).

- Scheme System:
**mbegin**`monad``mexp`... Bind

`mexp`and the following monadic expressions in sequence, returning the result of the last expression.This is akin to

`mlet`

, except that the return values of the monadic expressions are ignored. In that sense, it is analogous to`begin`

, but applied to monadic expressions.

The `(guix monads)`

module provides the *state monad*, which
allows an additional value—the state—to be *threaded* through
monadic procedure calls.

- Scheme Variable:
**%state-monad** The state monad. Procedures in the state monad can access and change the state that is threaded.

Consider the example below. The

`square`

procedure returns a value in the state monad. It returns the square of its argument, but also increments the current state value:(define (square x) (mlet %state-monad ((count (current-state))) (mbegin %state-monad (set-current-state (+ 1 count)) (return (* x x))))) (run-with-state (sequence %state-monad (map square (iota 3))) 0) ⇒ (0 1 4) ⇒ 3

When “run” through

`%state-monad`, we obtain that additional state value, which is the number of`square`

calls.

- Monadic Procedure:
**current-state** Return the current state as a monadic value.

- Monadic Procedure:
**set-current-state**`value` Set the current state to

`value`and return the previous state as a monadic value.

- Monadic Procedure:
**state-push**`value` Push

`value`to the current state, which is assumed to be a list, and return the previous state as a monadic value.

- Monadic Procedure:
**state-pop** Pop a value from the current state and return it as a monadic value. The state is assumed to be a list.

- Scheme Procedure:
**run-with-state**`mval`[`state`] Run monadic value

`mval`starting with`state`as the initial state. Return two values: the resulting value, and the resulting state.

The main interface to the store monad, provided by the ```
(guix
store)
```

module, is as follows.

- Scheme Variable:
**%store-monad** The store monad—an alias for

`%state-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 below.)

- Scheme Procedure:
**run-with-store**`store``mval`[#:guile-for-build] [#:system (%current-system)] Run

`mval`, a monadic value in the store monad, in`store`, an open store connection.

- Monadic Procedure:
**text-file**`name``text`[`references`] Return as a monadic value the absolute file name in the store of the file containing

`text`, a string.`references`is a list of store items that the resulting text file refers to; it defaults to the empty list.

- Monadic Procedure:
**interned-file**`file`[`name`] [#:recursive? #t] Return the name of

`file`once interned in the store. Use`name`as its store name, or the basename of`file`if`name`is omitted.When

`recursive?`is true, the contents of`file`are added recursively; if`file`designates a flat file and`recursive?`is true, its contents are added, and its permission bits are kept.The example below adds a file to the store, under two different names:

(run-with-store (open-connection) (mlet %store-monad ((a (interned-file "README")) (b (interned-file "README" "LEGU-MIN"))) (return (list a b)))) ⇒ ("/gnu/store/rwm…-README" "/gnu/store/44i…-LEGU-MIN")

The `(guix packages)`

module exports the following package-related
monadic procedures:

- Monadic Procedure:
**package-file**`package`[`file`] [#:system (%current-system)] [#:target #f] [#:output "out"] Return as a monadic 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`. When`target`is true, use it as a cross-compilation target triplet.

- Monadic Procedure:
**package->derivation**`package`[`system`] - Monadic Procedure:
**package->cross-derivation**`package``target`[`system`] Monadic version of

`package-derivation`

and`package-cross-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.

Next: G-Expressions, Previous: Derivations, Up: Programming Interface [Contents][Index]