Next: Expresiones-G, Previous: Derivaciones, Up: Interfaz programática [Contents][Index]
Los procedimientos que operan en el almacén descritos en la sección previa toman todos una conexión abierta al daemon de construcción en su primer parámetro. Aunque el modelo subyacente es funcional, tienen o bien efectos secundarios o dependen del estado actual del almacén.
Lo anterior es inconveniente: la conexión al daemon de construcción tiene que proporcionarse en todas estas funciones, haciendo imposible la composición de funciones que no toman ese parámetro con funciones que sí lo hacen. Lo último puede ser problemático: ya que las operaciones del almacén tienen efectos secundarios y/o dependen del estado externo, deben ser secuenciadas de manera adecuada.
Aquí es donde entra en juego el módulo (guix monads)
. Este módulo
proporciona un entorno para trabajar con mónadas, y una mónada
particularmente útil para nuestros usos, la mónada del almacén. Las
mónadas son una construcción que permite dos cosas: asociar “contexto” con
valores (en nuestro caso, el contexto es el almacén), y la construcción de
secuencias de computaciones (aquí computaciones incluye accesos al
almacén). Los valores en una mónada—valores que transportan este contexto
adicional—se llaman valores monádicos; los procedimientos que
devuelven dichos valores se llaman procedimientos monádicos.
Considere este procedimiento “normal”:
(define (enlace-sh almacen)
;; Devuelve una derivación que enlaza el ejecutable 'bash'.
(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))))
Mediante el uso de (guix monads)
y (guix gexp)
, puede
reescribirse como una función monádica:
(define (enlace-sh)
;; Lo mismo, pero devuelve un valor monádico.
(mlet %store-monad ((drv (package->derivation bash)))
(gexp->derivation "sh"
#~(symlink (string-append #$drv "/bin/bash")
#$output))))
Hay varias cosas a tener en cuenta en la segunda versión: el parámetro
store
ahora es implícito y es “hilado en las llamadas a los
procedimientos monádicos package->derivation
y
gexp->derivation
, y el valor monádico devuelto por
package->derivation
es asociado mediante el uso de mlet
en vez de un simple let
.
Al final, la llamada a package->derivation
puede omitirse ya que
tendrá lugar implícitamente, como veremos más adelante
(see Expresiones-G):
(define (enlace-sh)
(gexp->derivation "sh"
#~(symlink (string-append #$bash "/bin/bash")
#$output)))
La ejecución del procedimiento monádico enlace-para-sh
no tiene
ningún efecto. Como alguien dijo una vez, “sales de una mónada como sales
de un edificio en llamas: corriendo” (run en inglés). Por tanto, para salir
de la mónada y obtener el efecto deseado se debe usar run-with-store
:
(run-with-store (open-connection) (enlace-sh)) ⇒ /gnu/store/...-enlace-para-sh
Note that the (guix monad-repl)
module extends the Guile REPL with
new “commands” to make it easier to deal with monadic procedures:
run-in-store
, and enter-store-monad
(see Using Guix Interactively). 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 => …>
El último entra en un entorno interactivo recursivo, donde todos los valores devueltos se ejecutan automáticamente a través del almacén:
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)>
Fíjese que los valores no-monádicos no pueden devolverse en el entorno
interactivo store-monad
.
Other meta-commands are available at the REPL, such as ,build
to
build a file-like object (see Using Guix Interactively).
Las formas sintácticas principales para tratar con mónadas en general se
proporcionan por el módulo (guix monads)
y se describen a
continuación.
Evalúa cualquier forma >>=
o return
en cuerpo como
estando en mónada.
Devuelve el valor monádico que encapsula val.
Asocia el valor monádico mval, pasando su “contenido” a los procedimientos monádicos mproc…24. Puede haber un mproc o varios, como en este ejemplo:
(run-with-state (with-monad %state-monad (>>= (return 1) (lambda (x) (return (+ 1 x))) (lambda (x) (return (* 2 x))))) 'un-estado) ⇒ 4 ⇒ un-estado
mval en cuerpo, el cual es una secuencia de expresiones. Como
con el operador bind, esto puede pensarse como el “desempaquetado” del
valor crudo no-monádico dentro del ámbito del cuerpo. La forma
(var -> val) asocia var al valor “normal” val,
como en let
. Las operaciones de asociación ocurren en secuencia de
izquierda a derecha. La última expresión de cuerpo debe ser una
expresión monádica, y su resultado se convertirá en el resultado de
mlet
o mlet*
cuando se ejecute en la mónada.
mlet*
es a mlet
lo que let*
es a let
(see Local Bindings in GNU Guile Reference Manual).
Asocia mexp y las siguientes expresiones monádicas en secuencia, devolviendo el resultado de la última expresión. Cada expresión en la secuencia debe ser una expresión monádica.
Esto es similar a mlet
, excepto que los valores devueltos por las
expresiones monádicas se ignoran. En ese sentido el funcionamiento es
análogo a begin
pero aplicado a expresiones monádicas.
Cuando condición es verdadero, evalúa la secuencia de expresiones
monádicas mexp0..mexp* como dentro de mbegin
. Cuando
condición es falso, devuelve *unespecified*
en la mónada
actual. Todas las expresiones en la secuencia deben ser expresiones
monádicas.
Cuando condición es falso, evalúa la secuencia de expresiones
monádicas mexp0..mexp* como dentro de mbegin
. Cuando
condición es verdadero, devuelve *unespecified*
en la mónada
actual. Todas las expresiones en la secuencia deben ser expresiones
monádicas.
El módulo (guix monads)
proporciona la mónada de estado, que
permite que un valor adicional—el estado—sea hilado a través de
las llamadas a procedimientos monádicos.
La mónada de estado. Procedimientos en la mónada de estado pueden acceder y cambiar el estado hilado.
Considere el siguiente ejemplo. El procedimiento cuadrado
devuelve un
valor en la mónada de estado.
(define (cuadrado 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 cuadrado (iota 3))) 0) ⇒ (0 1 4) ⇒ 3
Cuando se “ejecuta” a través de %state-monad
, obtenemos un valor
adicional de estado, que es el número de llamadas a cuadrado
.
Devuelve el estado actual como un valor monádico.
Establece el estado actual a valor y devuelve el estado previo como un valor monádico.
Apila valor al estado actual, que se asume que es una lista, y devuelve el estado previo como un valor monádico.
Extrae un valor del estado actual y lo devuelve como un valor monádico. Se asume que el estado es una lista.
Ejecuta un valor monádico mval comenzando con estado como el estado inicial. Devuelve dos valores: el valor resultante y el estado resultante.
La interfaz principal a la mónada del almacén, proporcionada por el módulo
(guix store)
, es como sigue.
La mónada del almacén—un alias para %state-monad
.
Los valores en la mónada del almacén encapsulan los accesos al
almacén. Cuando su efecto es necesario, un valor de la mónada del almacén
será “evaluado” cuando se proporcione al procedimiento
run-with-store
(véase a continuación).
Ejecuta mval, un valor monádico en la mónada del almacén, en almacén, una conexión abierta al almacén.
Devuelve como un valor monádico el nombre absoluto del archivo en el almacén del archivo que contiene ŧexto, una cadena. referencias es una lista de elementos del almacén a los que el archivo de texto referencia; su valor predeterminado es la lista vacía.
Devuelve como un valor monádico el nombre absoluto del archivo en el almacén del archivo que contiene datos, un vector de bytes. referencias es una lista de elementos del almacén a los que el archivo binario referencia; su valor predeterminado es la lista vacía.
Devuelve el nombre del archivo una vez internado en el almacén. Usa nombre como su nombre del almacén, o el nombre base de archivo si nombre se omite.
Cuando recursive? es verdadero, los contenidos del archivo se añaden recursivamente; si archivo designa un archivo plano y recursive? es verdadero, sus contenidos se añaden, y sus bits de permisos se mantienen.
Cuando recursive? es verdadero, llama a (select?
archivo stat)
por cada entrada del directorio, donde
archivo es el nombre absoluto de archivo de la entrada y stat es
el resultado de lstat
; excluyendo las entradas para las cuales
select? no devuelve verdadero.
El ejemplo siguiente añade un archivo al almacén, bajo dos nombres diferentes:
(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")
El módulo (guix packages)
exporta los siguientes procedimientos
monádicos relacionados con paquetes:
Devuelve como un valor monádico el nombre absoluto de archivo de archivo dentro del directorio de salida output del paquete. Cuando se omite archivo, devuelve el nombre del directorio de salida output del paquete. Cuando target es verdadero, se usa como una tripleta de compilación cruzada.
Tenga en cuenta que este procedimiento no construye paquete. Por lo tanto, el resultado puede designar o no un archivo existente. Le recomendamos que no use este procedimiento a no ser que sepa qué está haciendo.
Versión monádica de package-derivation
y
package-cross-derivation
(see Definición de paquetes).
Esta operación es habitualmente conocida como “bind” (asociación), pero ese nombre denota un procedimiento no relacionado en Guile. Por tanto usamos este símbolo en cierto modo críptico heredado del lenguaje Haskell.
Next: Expresiones-G, Previous: Derivaciones, Up: Interfaz programática [Contents][Index]