2014-02-04 2 views
7

Я посмотрел документацию algo.monads и fluokitten. Я также прочитал записи блога монады Jim Duey, Konrad Hinsen и Leonardo Borges.Возможно ли сделать Reader Monad от Haskell в Clojure?

Единственная ссылка, которую я могу найти для читающей монады в Clojure, - this google groups discussion.

Мой вопрос: Можно ли сделать Reader Monad from Haskell в Clojure? Не могли бы вы привести пример?

ответ

7

Несомненно. A Reader - это просто функция, которая берет среду и извлекает из нее некоторое значение.

С Reader, m-result принимает некоторое значение и производит читатель, который игнорирует окружающую среду и возвращает это значение:

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

m-bind берет читателя и функция f, которая принимает значение и производит новый читатель. Затем он сочетает в себе эти аргументы для создания нового читателя, который применяет первоначальный читателя к окружающей среде, питает значение, которое она производит на f для получения нового читателя, затем применяет этот читателя к окружающей среде:

(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)))) 

С помощью этих функций , мы можем определить Reader с algo.monads:

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

Есть несколько важных вспомогательных функций. run-reader берет читателя и окружающей среды и применяет читателя к этой среде:

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

Поскольку наши читатели только функции, run-reader не является строго необходимым. Однако это может сделать все более ясным, и это приближает нас к реализации Haskell, поэтому мы будем использовать его в будущем.

ask и asks давайте рассмотрим окружающую среду. ask - читатель, который возвращает среду. asks берет селектор и создает считыватель, который применяет этот селектор в среде:

(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))) 

Это получает нас достаточно далеко, чтобы пройти через first Reader example:

(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))) 

Другой важной функцией является Readerlocal. Это берет функцию, которая изменяет среду и читатель и создает новый читатель, который изменяет окружающую среду, прежде чем передать его к исходному читателю:

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

с этим, мы можем пройти через second example:

(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))) 

Итак, это все, что нужно, чтобы сделать Reader.

1

Есть некоторые фантастические примеры следующих монад in Clojure here:

  • читатель монада в Clojure
  • писатель монада в Clojure
  • состояние монады в Clojure
  • монада идентичность в Clojure
  • возможно монада в clojure
  • либо монада в clojure
Смежные вопросы