是否可以在Clojure中使用Haskell的Reader Monad?

时间:2014-02-04 10:57:16

标签: clojure monads reader-monad

我查看了algo.monadsfluokitten文档。我还通过Jim DueyKonrad HinsenLeonardo Borges阅读了monad博客条目。

我可以在Clojure中找到读者Monad的唯一参考是this google groups discussion

我的问题是:是否可以在Clojure中执行Reader Monad from Haskell您能提供一个示例吗?

2 个答案:

答案 0 :(得分:7)

不确定。 Reader只是一个获取环境并从中提取一些值的函数。

使用Readerm-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实现,因此我们将继续使用它。

askasks让我们检查环境。 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)))

另一个重要的Reader函数是local。这需要一个修改环境和阅读器的函数,并创建一个新的阅读器,在将环境传递给原始阅读器之前修改环境:

(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 :(得分:0)

以下monad in Clojure here有一些很棒的例子:

  • 读者monad in clojure
  • 作家monad in clojure
  • clojure中的州monad
  • clojure中的身份monad
  • 可能是monj in clojure
  • 任何monad in clojure