- > Clojure中的运算符

Dax*_*ohl 23 f# pipeline clojure

Clojure中的 - >运算符(以及在Clojure中调用的运算符是什么?)相当于F#中的管道运算符|>?如果是这样,当(|>)被定义为时,为什么它需要这样一个复杂的宏定义

let inline (|>) x f = f x
Run Code Online (Sandbox Code Playgroud)

或者如果没有,F#的管道运算符是否存在于Clojure中,或者您将如何在Clojure中定义这样的运算符?

ama*_*loy 32

不,他们不一样.Clojure中并没有真正有需要|>,因为所有的函数调用都包含在列表中,例如(+ 1 2):没有什么神奇的,你可以做,以使1 + 2工作在隔离.1

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

(-> x (assoc :name "ted") (dissoc :size) (keys))
Run Code Online (Sandbox Code Playgroud)

扩展到

(keys (dissoc (assoc x :name "ted") :size))
Run Code Online (Sandbox Code Playgroud)

前者通常更容易阅读,因为从概念上讲,您正在执行一系列操作x; 以前的代码是"塑造"的,而后者需要一些心理解开才能解决问题.

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


mik*_*era 11

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

它比你描述的|>运算符更强大,因为它旨在通过几个函数传递一个值,其中每个连续的值被"插入"作为以下函数调用的第一个参数.这是一个有点人为的例子:

(-> [1]
     (concat [2 3 4])
     (sum)
     ((fn [x] (+ x 100.0))))
=> 110.0
Run Code Online (Sandbox Code Playgroud)

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

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

(|> 3 inc)
=> 4
Run Code Online (Sandbox Code Playgroud)

不知道真的有多么有用,但无论如何你仍然存在:-)

最后,如果你想通过一系列函数传递一个值,你总是可以在clojure中做类似下面的事情:

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

(pipeline 1 inc inc inc inc)
=> 5
Run Code Online (Sandbox Code Playgroud)

  • 为什么说`->` 是“出于性能原因”的宏?这是一个宏,因为作为一个函数它不起作用。 (2认同)

Jul*_*ang 10

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

(->> a (+ 5) (let [a 5] ))
Run Code Online (Sandbox Code Playgroud)

Clojure的喜悦,第8.1章讨论了这个主题.


Ala*_*son 5

在阅读源代码时(特别是在说话时),我总是将->操作符称为"线程优先",->>操作符为"线程最后".

请记住,现在有一个as->比任何一个更灵活的运营商->->>. 表格是:

(as-> val name (form1 arg1 name arg2)...)
Run Code Online (Sandbox Code Playgroud)

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

user=> (-> :a 
           (vector 1))
[:a 1]
user=> (as-> :a it 
             (vector it 1) )
[:a 1]
Run Code Online (Sandbox Code Playgroud)

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

user=> (->> :a 
            (vector 2))
[2 :a]
user=> (as-> :a it 
             (vector 2 it) )
[2 :a]
Run Code Online (Sandbox Code Playgroud)

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

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"]
Run Code Online (Sandbox Code Playgroud)