clojure monads reader-monad

¿Es posible hacer el Reader Monad de Haskell en Clojure?



monads reader-monad (2)

Por supuesto. Un Reader es solo una función que toma un entorno y extrae algo de valor de él.

Con Reader , m-result toma algún valor y produce un lector que ignora el entorno y devuelve ese valor:

(defn reader-result [value] "Ignores environment, returns value" (fn [env] value))

m-bind toma un lector y una función f que acepta un valor y produce un nuevo lector. Luego combina esos argumentos para producir un nuevo lector que aplica el lector inicial a un entorno, alimenta el valor que produce para producir un nuevo lector y luego aplica ese lector al entorno:

(defn reader-bind [reader f] "Applies reader to environment, then applies f to new environment" (fn [env] (let [read-value (reader env)] ((f read-value) env))))

Con estas funciones, podemos definir Reader con algo.monads :

(m/defmonad Reader [m-result reader-result m-bind reader-bind])

Hay algunas funciones de ayuda importantes. run-reader toma un lector y entorno y aplica el lector a ese entorno:

(defn run-reader "Runs a reader against an environment, returns the resulting environment" [reader env] (reader env))

Dado que nuestros lectores son solo funciones, run-reader no es estrictamente necesario. Sin embargo, puede aclarar las cosas y nos mantiene más cerca de la implementación de Haskell, por lo que la usaremos para seguir adelante.

ask y asks vamos a examinar el entorno. ask es un lector que devuelve el entorno. asks toma un selector y crea un lector que aplica ese selector a un entorno:

(defn ask "A reader that returns the environment" [env] env) (defn asks "A reader that returns the result of f applied to the environment" [f] (fn [env] (f env)))

Esto nos lleva lo suficientemente lejos como para pasar por el primer ejemplo de Reader :

(defn lookup-var [name bindings] (get bindings name)) (def calc-is-count-correct? (m/domonad Reader [binding-count (asks #(lookup-var "count" %)) bindings ask] (= binding-count (count bindings)))) (defn is-count-correct? [bindings] (run-reader calc-is-count-correct? bindings)) (def sample-bindings {"count" 3, "1" 1, "b" 2}) (println (str "Count is correct for bindings " sample-bindings ": " (is-count-correct? sample-bindings)))

La otra función importante de Reader es local . Esto toma una función que modifica un entorno y un lector y crea un nuevo lector que modifica el entorno antes de pasarlo al lector original:

(defn local [modify reader] "A reader that modifies the environment before calling the original reader" (fn [env] (run-reader reader (modify env))))

Con eso, podemos pasar por el segundo ejemplo :

(def calc-content-len (m/domonad Reader [content ask] (count content))) (def calc-modified-content-len (local #(str "Prefix " %) calc-content-len)) (let [s "12345" modified-len (run-reader calc-modified-content-len s) len (run-reader calc-content-len s)] (println (str "Modified ''s'' length: " modified-len)) (println (str "Original ''s'' length: " len)))

Entonces, eso es todo lo que se necesita para hacer Reader .

He echado un vistazo al algo.monads y la documentación de Fluokitten . También he leído entradas de blog de mónada de Jim Duey , Konrad Hinsen y Leonardo Borges .

La única referencia que puedo encontrar al Reader Monad en Clojure es esta discusión de grupos de google .

Mi pregunta es: ¿es posible hacer el Reader Monad de Haskell en Clojure? Podría dar un ejemplo?


Hay algunos ejemplos fantásticos de las siguientes mónadas en Clojure aquí :

  • el lector mónada en clojure
  • el escritor mónada en clojure
  • la mónada estatal en clojure
  • la mónada de identidad en clojure
  • la tal vez mónada en clojure
  • la mónada en clojure