也许在 clojure 中
Maybe in clojure
尝试在 clojure 中编写一个在第一个 nil 值处退出的组合函数,(例如,您通过在 haskell 中将 Maybes 链接在一起来做的事情)具有以下内容:
(defn wrap [f] (fn [x] (if (nil? x) nil (f x))))
(defn maybe [arg & functs] ( (comp (reverse (map wrap functs))) arg))
这样我就可以得到,例如
(defn f1 [x] (+ x 1))
(maybe 1 f1 f1 ) => 3
(maybe nil f1 f1) => nil
不幸的是,这给了我这个:
ClassCastException clojure.lang.PersistentList 无法转换为 clojure.lang.IFn user/maybe (NO_SOURCE_FILE:1)
有人可以就我在这里做错的事情提供一些帮助吗?执行此操作的惯用方法是什么?
comp
期望每个函数作为单独的参数,但您将函数列表作为单个参数传递给它。要解决此问题,请使用 apply
.
(defn maybe [arg & functs] ( (apply comp (reverse (map wrap functs))) arg))
执行此操作的惯用方法是使用 some->
。有关详细信息,请参阅此宏的 the documentation。
当然,不要让那阻止你自己制作!
总有 clojure.algo.monads
命名空间和 maybe-m
单子:
(with-monad maybe-m
(defn adder [x]
(let [f (fn [x] (+ x 1))]
(domonad
[a x
b (f a)
c (f b)]
c))))
(adder 1)
=> 3
(adder nil)
=> nil
诚然,这对您的要求来说可能有点矫枉过正
我知道这个问题已经得到解答,我已经自己提出了一个,但我想我会添加以下内容,因为我再次使用 monads 来玩它,这对 [=32= 来说似乎是个好问题]反对。
阅读 this article on threading monads,我能够通过扩展文章中定义的 m->
宏来提出以下内容,以创建线程化的 maybe monad 以便更简单地使用。 TBH 它并不比使用 some->
更简单,但这是出于个人好奇心。
好的,首先要定义一些样板代码,这里(以防文章消失)是 Giles 的线程 monad 定义:
(defn bind-monadic-expr-into-form [insert form]
(list 'm-bind insert
(if (seq? form)
`(fn [bound#] (~(first form) bound# ~@(rest form)))
`(fn [bound#] (~form bound#)))))
(defmacro m->
([m x]
`(with-monad ~m ~x))
([m x form]
`(with-monad ~m
~(bind-monadic-expr-into-form x form)))
([m x form & more]
`(m-> ~m (m-> ~m ~x ~form) ~@more)))
现在,您可以将线程化的宏定义为
(defmacro maybe->
([x] `(m-> ~maybe-m ~x))
([x form] `(m-> ~maybe-m ~x ~form))
([x form & more] `(maybe-> (maybe-> ~x ~form) ~@more)))
并像这样使用它:
(maybe-> 1 inc)
=> 2
(maybe-> [1 2] (#(map inc %)))
=> (2 3)
(defn f1 [x] (+ 1 x))
(maybe-> 1 f1 f1)
=> 3
(maybe-> 1 f1 ((constantly nil)) f1)
=> nil
(maybe-> {:a 1 :b 2} :c inc)
=> nil
在这种情况下,使用它绝对没有 some->
的优势,但是 m->
monad 确实增加了一些有趣的能力,能够创建 fail->
宏,如我链接的文章,它提供的不仅仅是 "nil" 作为 return,让您能够区分失败原因。
尝试在 clojure 中编写一个在第一个 nil 值处退出的组合函数,(例如,您通过在 haskell 中将 Maybes 链接在一起来做的事情)具有以下内容:
(defn wrap [f] (fn [x] (if (nil? x) nil (f x))))
(defn maybe [arg & functs] ( (comp (reverse (map wrap functs))) arg))
这样我就可以得到,例如
(defn f1 [x] (+ x 1))
(maybe 1 f1 f1 ) => 3
(maybe nil f1 f1) => nil
不幸的是,这给了我这个: ClassCastException clojure.lang.PersistentList 无法转换为 clojure.lang.IFn user/maybe (NO_SOURCE_FILE:1)
有人可以就我在这里做错的事情提供一些帮助吗?执行此操作的惯用方法是什么?
comp
期望每个函数作为单独的参数,但您将函数列表作为单个参数传递给它。要解决此问题,请使用 apply
.
(defn maybe [arg & functs] ( (apply comp (reverse (map wrap functs))) arg))
执行此操作的惯用方法是使用 some->
。有关详细信息,请参阅此宏的 the documentation。
当然,不要让那阻止你自己制作!
总有 clojure.algo.monads
命名空间和 maybe-m
单子:
(with-monad maybe-m
(defn adder [x]
(let [f (fn [x] (+ x 1))]
(domonad
[a x
b (f a)
c (f b)]
c))))
(adder 1)
=> 3
(adder nil)
=> nil
诚然,这对您的要求来说可能有点矫枉过正
我知道这个问题已经得到解答,我已经自己提出了一个,但我想我会添加以下内容,因为我再次使用 monads 来玩它,这对 [=32= 来说似乎是个好问题]反对。
阅读 this article on threading monads,我能够通过扩展文章中定义的 m->
宏来提出以下内容,以创建线程化的 maybe monad 以便更简单地使用。 TBH 它并不比使用 some->
更简单,但这是出于个人好奇心。
好的,首先要定义一些样板代码,这里(以防文章消失)是 Giles 的线程 monad 定义:
(defn bind-monadic-expr-into-form [insert form]
(list 'm-bind insert
(if (seq? form)
`(fn [bound#] (~(first form) bound# ~@(rest form)))
`(fn [bound#] (~form bound#)))))
(defmacro m->
([m x]
`(with-monad ~m ~x))
([m x form]
`(with-monad ~m
~(bind-monadic-expr-into-form x form)))
([m x form & more]
`(m-> ~m (m-> ~m ~x ~form) ~@more)))
现在,您可以将线程化的宏定义为
(defmacro maybe->
([x] `(m-> ~maybe-m ~x))
([x form] `(m-> ~maybe-m ~x ~form))
([x form & more] `(maybe-> (maybe-> ~x ~form) ~@more)))
并像这样使用它:
(maybe-> 1 inc)
=> 2
(maybe-> [1 2] (#(map inc %)))
=> (2 3)
(defn f1 [x] (+ 1 x))
(maybe-> 1 f1 f1)
=> 3
(maybe-> 1 f1 ((constantly nil)) f1)
=> nil
(maybe-> {:a 1 :b 2} :c inc)
=> nil
在这种情况下,使用它绝对没有 some->
的优势,但是 m->
monad 确实增加了一些有趣的能力,能够创建 fail->
宏,如我链接的文章,它提供的不仅仅是 "nil" 作为 return,让您能够区分失败原因。