Если я делаю следующее:
user=> (-> ["1" "2"] (partial apply str))
#<core$partial__5034$fn__5040 clojure.core$partial__5034$fn__5040@d4dd758>
... Я возвращаю частичную функцию. Однако, если я связываю его с переменной:
user=> (def apply-str (partial apply str))
#'user/apply-str
user=> (-> ["1" "2" "3"] apply-str)
"123"
... код работает, поскольку я предназначил это. Я предположил бы, что они - то же самое, но по-видимому который не имеет место. Кто-то может объяснить, почему это мне?
-> - это макрос, поэтому он не должен следовать правилам, которые вы ожидаете с точки зрения применения. Макрос преобразует источник перед оценкой форм. Попробуйте макрорасширение форм:
user> (macroexpand '(-> ["1" "2"] (partial apply str)))
(partial ["1" "2"] apply str)
Чего вы здесь пытаетесь достичь с помощью макроса '->'?
РЕДАКТИРОВАТЬ: Обратите внимание, что:
user> ((partial apply str) ["1" "2"])
"12"
Макрос ->
добавляет скобки вокруг apply-str
во второй версии, поэтому макрос расширяется для кода, который в конечном итоге вызывает вашу функцию. Посмотрите на исходный код для ->
, и вы увидите:
(defmacro ->
"Threads the expr through the forms. Inserts x as the
second item in the first form, making a list of it if it is not a
list already. If there are more forms, inserts the first form as the
second item in second form, etc."
([x] x)
([x form] (if (seq? form)
(with-meta `(~(first form) ~x ~@(next form)) (meta form))
(list form x)))
([x form & more] `(-> (-> ~x ~form) ~@more)))
Соответствующая часть - это когда он имеет дело с двумя аргументами, x
и формой
. Если форма
является последовательностью, x
вставляется в качестве второго аргумента в этот список. В противном случае макрос помещает форму
и x
в сам список. Это сделано для того, чтобы вы могли использовать пустой символ как сокращение для списка, содержащего один символ.
user> (macroexpand '(-> 123 (foo)))
(foo 123)
user> (macroexpand '(-> 123 foo))
(foo 123)
Вам вовсе не обязательно это делать.
(->> ["1" "2" "3"] (apply str))
Почему бы не сделать это вместо этого?
Первое выражение, (-> ["1" "2"] (частично применить str))
, заменяется на:
(partial ["1" "2"] apply str)
, что в основном означает:
Создайте функцию из ["1" "2"]
(которая также является функцией, поскольку векторы являются функциями индексных ключей!) С помощью Vars apply
и str
уже указаны в качестве первых двух аргументов. Эта функция печатается как странная строка #
.
Только когда эта функция будет вызвана, вы получите исключение IllegalArgumentException, поскольку векторы принимают только один целочисленный аргумент, а не два аргумента Var.
Макрос -> Передает выражение через формы в качестве второго аргумента. В вашем случае заканчивается расширением до: (partial ["1" "2"] apply str)
, создавая четную функцию на основе вектора.
Но вы хотите вызвать четную функцию, основанную на apply и str в многопоточном выражении, и, следовательно, вам необходимо:
(-> ["1" "2"] ((partial apply str)))
Что ж: этот код довольно запутанный и не идиоматический Clojure.