Подтвердить что ты не робот

-> в Clojure

Является ли оператор → в Clojure (и что это оператор, вызываемый в Clojure -speak?), эквивалентный оператору конвейера | > в F #? Если да, то зачем нужно такое сложное определение макроса, когда (| > ) просто определяется как

let inline (|>) x f = f x

Или, если нет, существует ли оператор конвейера F # в Clojure или как вы определяете такой оператор в Clojure?

4b9b3361

Ответ 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"]