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

макрос многопоточности → с анонимными функциями

Я понимаю, что макрос '-> theading в Clojure применяет все функции, предоставленные для данного аргумента. Однако он не работает с анонимными функциями. Например:

user> (-> 4 inc inc dec)
5

Но:

user> (-> 4 #(+ % 1) #(- % 1) #(+ % 1))

Возвращает ошибку:

clojure.lang.Symbol cannot be cast to clojure.lang.IPersistentVector
[Thrown class java.lang.ClassCastException]

Если кто-то знает способ обойти это было бы полезно. Спасибо!

4b9b3361

Ответ 1

У вас могут быть анонимные функции в макросах Clojure. У вас проблемы, потому что вам не хватает скобок.:) Ваш пример редактируется ниже.

(-> 4 (#(+ % 1)) (#(- % 1)) (#(+ % 1)))

Ответ 2

(это основано на ответе на вопрос, который я разместил в комментариях).

макрос -> принимает каждый аргумент, делая его списком, если необходимо (применяя "необработанные" функции без аргументов - преобразуя myfunc в (myfunc)), а затем вставляет первый аргумент в -> качестве второго аргумента в каждом из этих списков.

так (-> foo myfunc) становится (-> foo (myfunc)) становится (myfunc foo), примерно.

все это описано в rel=noreferrer>документации для ->.

проблема с анонимными функциями заключается в том, что они генерируются макросом чтения, как описано здесь (прокрутка вниз). это означает, что #(...) преобразуется (до нормального расширения макроса) в (fn [...]...). что хорошо, но, что очень важно, это уже список.

таким образом, макрос считает, что анонимная функция уже применяется, когда фактически она сталкивается с определением функции (оба являются списками). и добавление "лишних" паренов - как описано выше в другом ответе - применяет анонимную функцию без аргументов.

причина этого неинтуитивного поведения заключается в том, что эвристика dwim (do-what-i-mean, а не dwim-witted, хотя...), используемая макросом ->, добавлена для того, чтобы вы могли скорее предоставлять "голые" функции чем требование, чтобы вы применяли их без аргументов, заключая их в список, это просто эвристика - она просто проверяет список - и запутывается определением функции, созданным макросом reader.

[по моему недобросовестному мнению, -> плохо реализовано и должно вместо этого отклонять все "голые" функции, а не только принимать приложения функций; тогда это будет казаться более последовательным. если нет, то, по крайней мере, документы могут быть более понятными, объясняя мотивирующую семантику, стоящую за размещением вещей в списках.]

Ответ 3

Ваш конкретный случай можно было бы решить просто используя:

(-> 4 (+ 1) (- 1) (+ 1))

где первый макрос потока -> позаботится о вставке результата предыдущего шага в качестве первого аргумента в "текущую" функцию.

Путаница возникает из-за того, что -> не является функцией, а макросом, и в этом случае аргументы обрабатываются по-разному, как объясняется другими ответами.