-> Clojure 中的运算符

发布于 2024-11-09 16:15:34 字数 228 浏览 4 评论 0 原文

是-> Clojure 中的运算符(这个运算符在 Clojure 中被称为什么?)相当于管道运算符 |>在 F# 中?如果是这样,为什么它需要如此复杂的宏定义,而 (|>) 只是定义为

let inline (|>) x f = f x

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

Is the -> operator in Clojure (and what is this operator called in Clojure-speak?) equivalent to the pipeline operator |> in F#? If so, why does it need such a complex macro definition, when (|>) is just defined as

let inline (|>) x f = f x

Or if not, does F#'s pipeline operator exist in Clojure, or how would you define such an operator in Clojure?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

入怼 2024-11-16 16:15:34

不,它们不一样。 Clojure 并不真正需要 |> 因为所有函数调用都包含在列表中,例如 (+ 1 2):您没有什么魔法可以使1 + 2 独立工作1

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

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

Expands to

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

The 前者通常更容易阅读,因为从概念上讲,您正在对 x 执行一系列操作;前一种代码就是这样“塑造”的,而后者则需要一些精神上的解构才能解决。

1 您可以编写一个宏来实现此目的。这个想法是将宏包装在要转换的整个源代码树中,并让它查找 |> 符号;然后它可以将源转换为您想要的形状。 Hiredman 使以一种非常 Haskell 风格的方式编写代码成为可能,他的 功能性包。

No, they are not the same. Clojure doesn't really have a need for |> because all function calls are enclosed in lists, like (+ 1 2): there's no magic you could do to make 1 + 2 work in isolation.1

-> is for reducing nesting and simplifying common patterns. For example:

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

Expands to

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

The former is often easier to read, because conceptually you're performing a series of operations on x; the former code is "shaped" that way, while the latter needs some mental unraveling to work out.

1 You can write a macro that sorta makes this work. The idea is to wrap your macro around the entire source tree that you want to transform, and let it look for |> symbols; it can then transform the source into the shape you want. Hiredman has made it possible to write code in a very Haskell-looking way, with his functional package.

沐歌 2024-11-16 16:15:34

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

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

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

It's called the "thread" operator. It's written as a macro as opposed to a normal function for performance reasons and so that it can provide a nice syntax - i.e. it applies the transformation at compile time.

It's somewhat more powerful than the |> operator you describe, as it's intended to pass a value through several functions, where each successive value is "inserted" as the first parameter of the following function calls. Here's a somewhat contrived example:

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

If you want to define a function exactly like the F# operator you have described, you can do:

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

(|> 3 inc)
=> 4

Not sure how useful that really is, but there you are anyway :-)

Finally, if you want to pass a value through a sequence of functions, you can always do something like the following in clojure:

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

(pipeline 1 inc inc inc inc)
=> 5
把时间冻结 2024-11-16 16:15:34

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

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

The Joy of Clojure,第 8.1 章稍微讨论了这个主题。

It is also worth noting that there is a ->> macro which will thread the form as the last argument:

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

The Joy of Clojure, chapter 8.1 talks about this subject a bit.

与之呼应 2024-11-16 16:15:34

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

请记住,现在有一个运算符 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"]

我经常使用最后一种形式,我在 it-> ="noreferrer">图珀洛库

(it-> 1
      (inc it)                                  ; thread-first or thread-last
      (+ it 3)                                  ; thread-first
      (/ 10 it)                                 ; thread-last
      (str "We need to order " it " items." )   ; middle of 3 arguments

  ;=> "We need to order 2 items." )

When reading source code (especially when speaking), I always pronounce the -> operator as "thread-first", and the ->> operator as "thread-last".

Keep in mind that there is now an operator as-> which is more flexible than either -> or ->>. The form is:

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

The value val is evaluated and assigned to the placeholder symbol name, which the user can place in ANY position in the following forms. I usually choose the word "it" for the placeholder symbol. We can mimic thread-first -> like so:

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

We can mimic thread-last ->> like so:

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

Or, we can combine them in a single expression:

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"]

I use this last form so much I have made a new operator it-> in the Tupelo Library:

(it-> 1
      (inc it)                                  ; thread-first or thread-last
      (+ it 3)                                  ; thread-first
      (/ 10 it)                                 ; thread-last
      (str "We need to order " it " items." )   ; middle of 3 arguments

  ;=> "We need to order 2 items." )
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文