Ответ 1
У вас могут быть анонимные функции в макросах Clojure. У вас проблемы, потому что вам не хватает скобок.:) Ваш пример редактируется ниже.
(-> 4 (#(+ % 1)) (#(- % 1)) (#(+ % 1)))
Я понимаю, что макрос '-> 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]
Если кто-то знает способ обойти это было бы полезно. Спасибо!
У вас могут быть анонимные функции в макросах Clojure. У вас проблемы, потому что вам не хватает скобок.:) Ваш пример редактируется ниже.
(-> 4 (#(+ % 1)) (#(- % 1)) (#(+ % 1)))
(это основано на ответе на вопрос, который я разместил в комментариях).
макрос ->
принимает каждый аргумент, делая его списком, если необходимо (применяя "необработанные" функции без аргументов - преобразуя myfunc
в (myfunc)
), а затем вставляет первый аргумент в ->
качестве второго аргумента в каждом из этих списков.
так (-> foo myfunc)
становится (-> foo (myfunc))
становится (myfunc foo)
, примерно.
все это описано в rel=noreferrer>документации для ->
.
проблема с анонимными функциями заключается в том, что они генерируются макросом чтения, как описано здесь (прокрутка вниз). это означает, что #(...)
преобразуется (до нормального расширения макроса) в (fn [...]...)
. что хорошо, но, что очень важно, это уже список.
таким образом, макрос считает, что анонимная функция уже применяется, когда фактически она сталкивается с определением функции (оба являются списками). и добавление "лишних" паренов - как описано выше в другом ответе - применяет анонимную функцию без аргументов.
причина этого неинтуитивного поведения заключается в том, что эвристика dwim (do-what-i-mean, а не dwim-witted, хотя...), используемая макросом ->
, добавлена для того, чтобы вы могли скорее предоставлять "голые" функции чем требование, чтобы вы применяли их без аргументов, заключая их в список, это просто эвристика - она просто проверяет список - и запутывается определением функции, созданным макросом reader.
[по моему недобросовестному мнению, ->
плохо реализовано и должно вместо этого отклонять все "голые" функции, а не только принимать приложения функций; тогда это будет казаться более последовательным. если нет, то, по крайней мере, документы могут быть более понятными, объясняя мотивирующую семантику, стоящую за размещением вещей в списках.]
Ваш конкретный случай можно было бы решить просто используя:
(-> 4 (+ 1) (- 1) (+ 1))
где первый макрос потока ->
позаботится о вставке результата предыдущего шага в качестве первого аргумента в "текущую" функцию.
Путаница возникает из-за того, что ->
не является функцией, а макросом, и в этом случае аргументы обрабатываются по-разному, как объясняется другими ответами.