Haskell';s<;-?

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

我试图找出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中实现绑定。