-> в Clojure
Является ли оператор → в Clojure (и что это оператор, вызываемый в Clojure -speak?), эквивалентный оператору конвейера | > в F #? Если да, то зачем нужно такое сложное определение макроса, когда (| > ) просто определяется как
let inline (|>) x f = f x
Или, если нет, существует ли оператор конвейера F # в Clojure или как вы определяете такой оператор в Clojure?
Ответы
Ответ 1
Нет, они не то же самое. Clojure действительно не нуждается в |>
, потому что все вызовы функций заключены в списки, например (+ 1 2)
: нет никакой магии, которую вы могли бы сделать, чтобы сделать 1 + 2
работать изолированно. 1
->
предназначен для уменьшения вложенности и упрощения общих паттернов. Например:
(-> x (assoc :name "ted") (dissoc :size) (keys))
Расширяется до
(keys (dissoc (assoc x :name "ted") :size))
Бывший часто легче читать, потому что концептуально вы выполняете серию операций на x
; прежний код "сформирован" таким образом, в то время как последний нуждается в умственном распутывании для разработки.
1 Вы можете написать макрос, который sorta делает эту работу. Идея состоит в том, чтобы обернуть ваш макрос вокруг всего исходного дерева, которое вы хотите преобразовать, и позволить ему искать символы |>
; он может затем преобразовать источник в нужную вам форму. Hiredman позволил написать код очень интересным способом, с его пакетом functional.
Ответ 2
Он называется оператором "поток". Он написан как макрос в отличие от обычной функции по соображениям производительности и поэтому может обеспечить хороший синтаксис - т.е. Он применяет преобразование во время компиляции.
Он несколько более мощный, чем оператор | > , который вы описываете, поскольку он предназначен для передачи значения через несколько функций, где каждое последующее значение "вставлено" в качестве первого параметра следующих вызовов функций. Вот несколько надуманный пример:
(-> [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
Ответ 3
Также стоит отметить, что существует - → macro, который выведет форму в качестве последнего аргумента:
(->> a (+ 5) (let [a 5] ))
Радость Clojure, глава 8.1 немного говорит об этом предмете.
Ответ 4
При чтении исходного кода (особенно при разговоре), я всегда произношу оператор ->
как "нить-первый", а оператор ->>
- как "нить-последний".
Имейте в виду, что теперь существует оператор as->
, который более гибкий, чем ->
или ->>.
. Форма:
(as-> val name (form1 arg1 name arg2)...)
Значение val
оценивается и присваивается символу-заполнителю name
, который пользователь может разместить в ЛЮБОЙ позиции в следующих формах. Я обычно выбираю слово "это" для символа-заполнителя. Мы можем имитировать thread-first ->
следующим образом:
user=> (-> :a
(vector 1))
[:a 1]
user=> (as-> :a it
(vector it 1) )
[:a 1]
Мы можем имитировать thread-last ->>
следующим образом:
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"]