Haskell';s<;-?
我试图找出IO单子和Haskell';s<;-?,haskell,clojure,monads,Haskell,Clojure,Monads,我试图找出IO单子和Do符号只是标准单子操作的糖分。例如,如果您有如下内容: do x <- someMonad return (someFunction x) (m-bind some-monad (fn [x] (m-result (some-function x)))) (fn [world] ; some stuff [value world]) (fn [io f] (fn [world] (let [[v new-world] (io
Do符号只是标准单子操作的糖分。例如,如果您有如下内容:
do
x <- someMonad
return (someFunction x)
(m-bind some-monad (fn [x] (m-result (some-function x))))
(fn [world]
; some stuff
[value world])
(fn [io f]
(fn [world]
(let [[v new-world] (io world)]
((f v) new-world))))
因此,使用许多monad库之一的等效Clojure可能是这样的:
do
x <- someMonad
return (someFunction x)
(m-bind some-monad (fn [x] (m-result (some-function x))))
(fn [world]
; some stuff
[value world])
(fn [io f]
(fn [world]
(let [[v new-world] (io world)]
((f v) new-world))))
我认为Chuck已经回答了您的主要问题,但如果您想以Clojure为例研究monad操作在Clojure中的实现方式,请参见以下内容:
(domonad state-m
[_ (set-state "foo")
x (fetch-state)]
x)
相当于(好吧,几乎,见下文)哈斯克尔的
do
_ <- put "foo" -- see below for a comment on this
x <- get
return x
do
_使用,我们可以很容易地定义IO单子(如果不必要的话)
在Haskell中,IO单子是类型IO a=World->(a,World)
。将其视为一种行动是很方便的——一种可以接受世界、做某事、返回价值和世界的行动
使用向量而不是元组,这意味着在Clojure中,IO操作(IO monad的一元值)看起来像这样:
do
x <- someMonad
return (someFunction x)
(m-bind some-monad (fn [x] (m-result (some-function x))))
(fn [world]
; some stuff
[value world])
(fn [io f]
(fn [world]
(let [[v new-world] (io world)]
((f v) new-world))))
要做一些有趣的事情,我们需要两个操作:getchar
和put char
get char
是一个在世界中执行的操作,读取一个字符,并将该字符作为其值与世界一起返回:
(defn read-char
[]
(-> *in* .read char))
(defn get-char
[world]
[(read-char) world])
put char
获取一个字符并创建一个动作,该动作在给定的世界中打印字符并返回一些(无关紧要的)值:
请注意,要采取行动,我们必须提供一个世界。例如,(put char\a)
将返回一个操作((put char\a:world)
将调用该操作,打印a
并返回[nil:world]
编写这些操作可能是一个非常混乱的过程。例如,如果您想获取一个字符,然后打印它,您必须调用get char
,解压缩其字符和世界,使用put char
为该字符创建一个操作,然后将世界传递给该操作
另一方面,如果我们定义monad,我们可以免费获得(相当于Haskell的do
)。这种语法糖减轻了拆包/包装样板的负担。我们只需要几个函数:m-result
和m-bind
(m-zero
和m-plus
也很方便,但不是必需的)
m-result
(return
在Haskell中)获取一个值并将其包装为一个操作:
(fn [v]
(fn [world]
[v world]))
m-bind
(>=
在Haskell中)执行一个操作和一个函数,该函数使用一个常规值来生成一个操作,通过调用该操作“展开”该值,并将该函数应用于该操作。对于IO monad,看起来是这样的:
do
x <- someMonad
return (someFunction x)
(m-bind some-monad (fn [x] (m-result (some-function x))))
(fn [world]
; some stuff
[value world])
(fn [io f]
(fn [world]
(let [[v new-world] (io world)]
((f v) new-world))))
因此,使用algo.monads
,我们可以定义io-m
,如下所示:
(defmonad io-m
[m-result (fn [v]
(fn [world]
[v world]))
m-bind (fn [io f]
(fn [world]
(let [[v new-world] (io world)]
((f v) new-world))))])
现在我们已经有了基本的IO操作和组合它们的方法,我们可以创建更有趣的操作。注意Haskell的解包操作符(注意=)
操作符(发音为bind)。由于(>>=)
是一种类方法(属于Monad
类),它有完全不同的实现,这取决于底层数据类型。它是如何为IO实现的?它没有包含一点澄清:谢谢Michal。。IO monad的实现方式是否与state相同?@zcaudate,是的,在某种程度上可能是。。。考虑阅读SPJ的一个主题,它可以为IO MUNAD提供一些有用的见解。我正在寻找一个具体的例子,说明如何使用Primf和RealLoad为IO单元格在Culjure中实现绑定。