也许在 clojure 中

问题描述 投票:0回答:4

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

有人可以为我在这里做错的事情提供一些帮助吗?执行此操作的惯用方法是什么?

clojure
4个回答
7
投票

执行此操作的惯用方法是使用

some->
。有关更多详细信息,请参阅此宏的文档

当然,不要让这阻止你自己制作!


4
投票

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

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

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

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


0
投票

我知道这个问题已经得到解答,我已经自己提出了一个,但我想我会添加以下内容,因为我再次使用 monad 来玩它,这似乎是一个很好的问题。

阅读这篇关于线程 monad 的文章,我能够通过扩展文章中定义的

m->
宏来创建一个线程化的 monad 以便更简单地使用,从而得出以下结论。老实说,它并不比仅使用
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”作为返回,使您能够区分失败原因。

© www.soinside.com 2019 - 2024. All rights reserved.