也许在clojure

时间:2015-05-14 16:13:41

标签: clojure

尝试在clojure中编写一个以第一个nil值出现的组合函数(例如,你通过将Maybes链接在haskell中来完成的事情),并使用以下代码:

(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用户/也许(NO_SOURCE_FILE:1)

有人可以帮我解决我在这里做错的事吗?这样做的惯用方法是什么?

4 个答案:

答案 0 :(得分:7)

执行此操作的惯用方法是使用some->。有关详细信息,请参阅此宏的the documentation

当然不要让那些阻止你制作自己的东西!

答案 1 :(得分:4)

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

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

答案 2 :(得分:4)

始终clojure.algo.monads命名空间与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

不可否认,你的要求可能有点过分

答案 3 :(得分:0)

我知道这已经得到了解答,而且我已经把自己放了一个,但我想我会添加以下内容,因为我再次使用monads进行游戏,这似乎是一个很好的问题。

阅读this article on threading monads,我能够通过扩展文章中定义的m->宏来创建一个线程化的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->宏,如文章I中所示链接,它提供的不仅仅是“零”作为回报,使您能够区分失败原因。