F# -&燃气轮机;Clojure中的运算符

F# -&燃气轮机;Clojure中的运算符,f#,clojure,pipeline,F#,Clojure,Pipeline,Clojure中的->运算符(在Clojure speak中该运算符叫什么?)是否与F#中的管道运算符|>等效?如果是这样,当(|>)被定义为 let inline (|>) x f = f x 或者如果没有,F#的管道操作符是否存在于Clojure中,或者您如何在Clojure中定义这样的操作符 不,它们不一样。Clojure实际上不需要|>,因为所有函数调用都包含在列表中,比如(+12):没有什么魔法可以让1+2独立工作。1 ->用于减少嵌套和简化常见模式。例如: (-> x

Clojure中的->运算符(在Clojure speak中该运算符叫什么?)是否与F#中的管道运算符|>等效?如果是这样,当(|>)被定义为

let inline (|>) x f = f x

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

不,它们不一样。Clojure实际上不需要
|>
,因为所有函数调用都包含在列表中,比如
(+12)
:没有什么魔法可以让
1+2
独立工作。1

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

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

(keys (dissoc (assoc x :name "ted") :size))
前者通常更容易阅读,因为从概念上讲,您正在
x
上执行一系列操作;前一个代码是这样“成形”的,而后一个代码则需要一些精神上的解释才能解决

1您可以编写一个宏,sorta使其工作。其思想是将宏环绕要转换的整个源代码树,并让它查找
|>
符号;然后,它可以将源转换为所需的形状。Hiredman用他的软件包以Haskell风格编写代码成为可能。

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

它比您描述的|>操作符功能更强,因为它旨在通过多个函数传递一个值,其中每个连续值都作为以下函数调用的第一个参数“插入”。下面是一个有点做作的例子:

(-> [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

还值得注意的是,有一个线程将窗体作为最后一个参数:

(->> a (+ 5) (let [a 5] ))
《Clojure的乐趣》,第8.1章稍微谈到了这个主题。

在阅读源代码时(尤其是在说话时),我总是将
->
操作符发音为“线程优先”,将
->
操作符发音为“线程最后”

请记住,现在有一个操作符
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]
我们可以像这样模拟线程last
->

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"]
我经常使用最后一个表单,因此我在中创建了一个新操作符
it->


我懂了。看起来线程操作符在Clojure中很有用,只是因为Clojure语法的工作方式在F#中没有用处。管道操作符也是如此。Clojure在操作中在第50页和第51页将这些宏的名称列为“线程优先”(>)和“线程最后”(>>)宏,尽管官方文档似乎没有给出它们的实际名称。@ShawnHolmes使用术语“线程优先”和“线程最后”。(该页面自2012年以来是新的。)为什么说
->
是“出于性能原因”的宏?它是一个宏,因为作为一个函数它是不起作用的。你可以用(->a#(…)#(…)#(…)#(…))(…)来获得类似的结果,即使“->”是一个函数,但使用起来既慢又有点难看:-)
(->b(a c)quote)
如果它不是宏,就永远无法计算为
(quote(a b c))
,还有其他类似的情况。
#(…)
案例将涉及到手工完成
->
已经完成的所有工作;你只需要将它制作成另一个版本的
comp
。是的,我完全同意,如果不使用宏,就无法获得完全相同的语法。我的观点是,您可以获得相同的功能,尽管需要更多的开销。无论哪种方式,我都在答案中添加了语法点。