是否可以在 Clojure 中从 Haskell 执行 Reader Monad? [英] Is it possible to do the Reader Monad from Haskell in Clojure?
问题描述
我查看了 algo.monads 和 fluokitten 文档.我还通读了 Jim Duey、Konrad Hinsen 和 莱昂纳多·博尔赫斯.
I've had a look at the algo.monads and fluokitten documentation. I've also read through monad blog entries by Jim Duey, Konrad Hinsen and Leonardo Borges.
我能在 Clojure 中找到 Reader Monad 的唯一参考是这个谷歌小组讨论.
The only reference I can find to the Reader Monad in Clojure is this google groups discussion.
我的问题是:是否可以执行 Clojure 中 Haskell 的 Reader Monad? 你能举个例子吗?
My question is: Is it possible to do the Reader Monad from Haskell in Clojure? Could you provide an example?
推荐答案
好的.Reader
只是一个接受环境并从中提取一些值的函数.
Sure. A Reader
is just a function that takes an environment and extracts some value from it.
使用 Reader
,m-result
获取一些值并生成一个忽略环境并返回该值的阅读器:
With Reader
, m-result
takes some value and produces a reader that ignores the environment and returns that value:
(defn reader-result
[value]
"Ignores environment, returns value"
(fn [env]
value))
m-bind
接受一个阅读器和一个函数 f
接受一个值并产生一个新的阅读器.然后它结合这些参数来产生一个新的阅读器,将初始阅读器应用到环境中,将它产生的值提供给 f
以生成一个新的阅读器,然后将该阅读器应用到环境中:
m-bind
takes a reader and a function f
that accepts a value and produces a new reader. It then combines those arguments to produce a new reader which applies the initial reader to an environment, feeds the value it produces to f
to produce a new reader, then applies that reader to the environment:
(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))))
通过这些函数,我们可以用algo.monads
来定义Reader
:
With these functions, we can define Reader
with algo.monads
:
(m/defmonad Reader
[m-result reader-result
m-bind reader-bind])
有几个重要的辅助函数.run-reader
接受阅读器和环境并将阅读器应用于该环境:
There are a few important helper functions. run-reader
takes a reader and environment and applies the reader to that environment:
(defn run-reader
"Runs a reader against an environment,
returns the resulting environment"
[reader env]
(reader env))
由于我们的读者只是函数,run-reader
并不是绝对必要的.但是,它可以使事情更清晰,并使我们更接近 Haskell 实现,因此我们将继续使用它.
Since our readers are just functions, run-reader
isn't strictly necessary. However, it can make things clearer and it keeps us closer to the Haskell implementation, so we'll use it going ahead.
ask
和 asks
让我们检查一下环境.ask
是一个返回环境的阅读器.asks
接受一个选择器并创建一个将选择器应用于环境的阅读器:
ask
and asks
let us examine the environment. ask
is a reader that returns the environment. asks
takes a selector and creates a reader that applies that selector to an environment:
(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)))
这让我们足够了解首先<代码>阅读器示例:
This gets us far enough to go through the 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
.这需要一个修改环境和阅读器的函数,并创建一个修改环境的新阅读器,然后再将其传递给原始阅读器:
The other important Reader
function is local
. This takes a function that modifies an environment and a reader and creates a new reader that modifies the environment before passing it to the original reader:
(defn local
[modify reader]
"A reader that modifies the environment
before calling the original reader"
(fn [env]
(run-reader reader (modify env))))
有了这个,我们可以通过第二个例子:
With that, we can go through the 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
所需的全部.
So, that's all it takes to make Reader
.
这篇关于是否可以在 Clojure 中从 Haskell 执行 Reader Monad?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!