7

我查看了algo.monadsfluokitten文档。我还阅读了Jim DueyKonrad HinsenLeonardo Borges的 monad 博客文章。

我能在 Clojure 中找到的对 Reader Monad 的唯一参考是这个 google groups Discussion

我的问题是:是否可以在 Clojure 中使用 Haskell 的 Reader Monad ?你能举个例子吗?

4

2 回答 2

8

当然。AReader只是一个函数,它接受一个环境并从中提取一些值。

使用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 的实现,所以我们将继续使用它。

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

这让我们足够了解第一个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)))

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

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

有了这个,我们可以看第二个例子

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

于 2014-02-04T21:45:37.180 回答
0

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

  • clojure 中的 reader monad
  • clojure 中的作家单子
  • clojure 中的状态单子
  • clojure 中的身份单子
  • clojure 中的 Maybe monad
  • clojure 中的任一单子
于 2014-02-07T05:55:52.820 回答