- > Clojure的操作员

时间:2011-05-26 21:00:59

标签: f# clojure pipeline

是 - > Clojure中的运算符(以及在Clojure中调用的运算符是什么?)等效于管道运算符|>在F#?如果是这样,当(|>)被定义为

时,为什么它需要这样一个复杂的宏定义
let inline (|>) x f = f x

如果不是,Flo的管道运算符是否存在于Clojure中,或者您如何在Clojure中定义这样的运算符?

4 个答案:

答案 0 :(得分:32)

不,他们不一样。 Clojure并不真正需要|>,因为所有函数调用都包含在列表中,例如(+ 1 2):你无法做出让1 + 2孤立地工作的魔力< / EM> 1

->用于减少嵌套并简化常见模式。例如:

(-> x (assoc :name "ted") (dissoc :size) (keys))

扩展到

(keys (dissoc (assoc x :name "ted") :size))

前者通常更容易阅读,因为从概念上讲,您在x上执行了一系列操作;以前的代码是“塑造”的,而后者需要一些精神上的解决才能解决问题。

1 你可以编写一个使sorta能够工作的宏。我们的想法是围绕要转换的整个源树包装宏,并让它查找|>个符号;然后它可以将源转换为您想要的形状。 Hiredman使用functional包以非常Haskell的方式编写代码成为可能。

答案 1 :(得分:11)

它被称为“线程”运算符。由于性能原因,它被编写为宏而不是普通函数,因此它可以提供一个很好的语法 - 即它在编译时应用转换。

它比|&gt;更强大。您描述的运算符,因为它旨在通过多个函数传递值,其中每个连续值都作为以下函数调用的第一个参数“插入”。这是一个有点人为的例子:

(-> [1]
     (concat [2 3 4])
     (sum)
     ((fn [x] (+ x 100.0))))
=> 110.0

如果要定义一个与您所描述的F#运算符完全相同的函数,可以执行以下操作:

(defn |> [x f] (f x))

(|> 3 inc)
=> 4

不确定实际有多么有用,但无论如何你仍然存在: - )

最后,如果你想通过一系列函数传递一个值,你总是可以在clojure中执行以下操作:

(defn pipeline [x & fns]
  ((apply comp fns) x))

(pipeline 1 inc inc inc inc)
=> 5

答案 2 :(得分:10)

值得注意的是,有一个->> macro将表格作为最后一个参数:

(->> a (+ 5) (let [a 5] ))

欢乐的Clojure,第8.1章讨论了这个主题。

答案 3 :(得分:5)

在阅读源代码时(尤其是在说话时),我总是将->运算符称为“线程优先”,将->>运算符称为“线程最后”。

请注意,现在有一个运算符as->->->>.更灵活。表单为:

(as-> val name (form1 arg1 name arg2)...)

评估值val并将其分配给占位符符号name,用户可以将其放置在以下表单中的任何位置。我通常会为占位符符号选择“it”这个词。我们可以像这样模仿线程优先->

user=> (-> :a 
           (vector 1))
[:a 1]
user=> (as-> :a it 
             (vector it 1) )
[:a 1]

我们可以像这样模仿线程最后->>

user=> (->> :a 
            (vector 2))
[2 :a]
user=> (as-> :a it 
             (vector 2 it) )
[2 :a]

或者,我们可以将它们组合在一个表达式中:

user=> (as-> :a it 
             (vector it 1) 
             (vector 2 it))
[2 [:a 1]]

user=> (as-> :a it 
             (vector it 1) 
             (vector 2 it) 
             (vector "first" it "last"))
["first" [2 [:a 1]] "last"]