- >/ - >>管道中的条件元素

Cha*_*ffy 11 clojure

给定->>像这样的管道:

(defn my-fn []
  (->> (get-data)
       (do-foo)
       (do-bar)
       (do-baz)))
Run Code Online (Sandbox Code Playgroud)

我希望各个阶段都有条件.

想到的第一种写作方式就是这样:

(defn my-fn [{:keys [foo bar baz]}]
  (->> (get-data)
       (if foo (do-foo) identity)
       (if bar (do-bar) identity)
       (if baz (do-baz) identity))
Run Code Online (Sandbox Code Playgroud)

但是,当->>宏试图插入if表单时,这不仅在性能方面看起来很不幸(有noop identity调用),而且实际上无法编译.

什么是合适的,合理干燥的写作方式是什么?

小智 9

您可能对这些宏https://github.com/pallet/thread-expr感兴趣


Dav*_*ann 9

Modern Clojure(即1.5版)支持条件线程的各种选项.

as->也许是最通用的,通过给你一个名称来引用穿过表格的"事物".例如:

(as-> 0 n
  (inc n)
  (if false
    (inc n)
    n))
=> 1

(as-> 0 n
  (inc n)
  (if true
    (inc n)
    n))
=> 2
Run Code Online (Sandbox Code Playgroud)

当使用需要在参数列表中的不同点处线程化表达式的混合函数(即,从 - >切换到 - >>语法)时,这提供了很大的灵活性.为了代码可读性,应该避免使用无关的命名变量,但这通常是表达过程最清晰,最简单的方法.

还有cond->,它要求一组对:测试和表达式,如果该测试评估为真.这非常相似,cond但并未停留在第一次真正的测试中.


Don*_*Don 7

这也有效:

(defn my-fn [{:keys [foo bar baz]}]
  (->> (get-data)
       (#(if foo (do-foo %) %))
       (#(if bar (do-bar %) %))
       (#(if baz (do-baz %) %)) ))
Run Code Online (Sandbox Code Playgroud)


Art*_*ldt 5

您可以修复编译部分(虽然不是苦行部分,通过让if 语句通过放置另一组来决定要运行函数( )如下所示:

(defn my-fn [{:keys [foo bar baz]}]
  (->> (get-data)
   ((if foo do-foo identity))
   ((if bar do-bar identity))
   ((if baz do-baz identity)))
Run Code Online (Sandbox Code Playgroud)

将扩展为一系列如下调用:

   ;  choose function         and call it    
   ( (if foo do-foo identity) args       )
   ( (if bar do-bar identity) args       )
   ( (if baz do-baz identity) args       )
Run Code Online (Sandbox Code Playgroud)


Ale*_*art 5

如果你经常需要这种东西,那么更常见的方法是:

(defn comp-opt [& flag-fns]
  (->> flag-fns
    (partition 2)
    (filter first)
    (map second)
    (apply comp)))

(defn my-fn [{:keys [foo bar baz]}]
  (map (comp-opt foo do-foo
                 bar do-bar
                 baz do-baz)
       (get-data)))