也许在clojure

也许在clojure,clojure,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 ) =

尝试在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(无源文件:1)


有人能帮我解释一下我做错了什么吗?实现这一点的惯用方法是什么?

comp
要求每个函数作为一个单独的参数,但您将函数列表作为一个单独的参数传递给它。要解决此问题,请使用
apply

(defn maybe [arg & functs] ( (apply comp (reverse (map wrap functs))) arg))

comp
要求每个函数作为一个单独的参数,但您将函数列表作为单个参数传递给它。要解决此问题,请使用
apply

(defn maybe [arg & functs] ( (apply comp (reverse (map wrap functs))) arg))

实现这一点的惯用方法是使用
some->
。有关详细信息,请参阅此宏的第页


当然,不要让这阻止你自己做

实现这一点的惯用方法是使用
some->
。有关详细信息,请参阅此宏的第页


当然,不要让这阻止你自己做

总是有
clojure.algo.monad
名称空间和
maybe-m
monad:

(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

诚然,对于您的需求来说,这可能有点过分了

始终存在
clojure.algo.monad
名称空间和
maybe-m
monad:

(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玩过它,这似乎是一个很好的问题

在阅读本文时,我通过扩展本文中定义的
m->
宏,创建了一个线程化的monad,以简化使用,从而得出了以下结论。TBH它并不比仅仅使用
some->
更简单,但这是出于个人好奇心

好的,首先要定义一些一次性的锅炉板代码,这里(以防文章消失)是Giles的线程单子定义:

(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”作为回报,给你区分失败原因的能力。

我知道这已经得到了回答,我自己也已经给出了一个答案,但我想我应该添加以下内容,因为我再次使用monads玩过它,这似乎是一个很好的问题

在阅读本文时,我通过扩展本文中定义的
m->
宏,创建了一个线程化的monad,以简化使用,从而得出了以下结论。TBH它并不比仅仅使用
some->
更简单,但这是出于个人好奇心

好的,首先要定义一些一次性的锅炉板代码,这里(以防文章消失)是Giles的线程单子定义:

(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”作为回报,使您能够区分故障原因。

wrap做什么(和x(f x))不做什么?wrap做什么(和x(f x))不做什么?请注意,产生的用法略有不同;some->宏很好地将结果隐式地推送到表单中,并且是不可组合的,而maybe函数需要实际函数,但是是可组合的。e、 g.
(一些->[1](地图公司))
但是
(可能是[1]#(地图公司%))
@DaxFohl你的意思是因为它是一个宏,所以它是不可组合的吗?你评论中的两个片段有什么区别?@muhuk是的,它是不可组合的,因为它是一个宏;如果您想在运行时构建要以这种方式执行的函数列表,则不能使用
some->
。区别在于
(map inc)
很短,但它不是一个在
some->
宏之外编译的表达式。明白了。但它并没有真正使
some->
本身不可组合。如果必须的话,你还可以
(def#(map inc%)
,然后
(some->[1](f))
。@muhuk说你有
(defn runall[arg&functs]((comp(reverse functts))arg))
,只是
可能没有
wrap
。您可以在运行时在它们之间进行选择
(让[myfunc(如果可能运行的话)](myfunc输入f1 f2 f3))
。无法使用
某些->
执行此操作。这就是人们说宏是不可组合的意思;some->宏很好地将结果隐式地推送到表单中,并且是不可组合的,而maybe函数需要实际函数,但是是可组合的。e、 g.
(一些->[1](地图公司))
但是
(可能是[1]#(地图公司%))
@DaxFohl你的意思是因为它是一个宏,所以它是不可组合的吗?你评论中的两个片段有什么区别?@muhuk是的,它是不可组合的,因为它是一个宏;如果您想在运行时构建要以这种方式执行的函数列表,则不能使用
some->
。区别在于
(map inc)
很短,但它不是一个在
some->
宏之外编译的表达式。明白了。但它并没有真正使
some->
本身不可组合。如果必须的话,你还可以
(def#(map inc%)
,然后
(some->[1](f))
。@muhuk说你有