(частичное применение str) и apply-str в clojure's -> - PullRequest
5 голосов
/ 05 апреля 2010

Если я сделаю следующее:

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"

... код работает так, как я задумал. Я бы предположил, что это одно и то же, но, очевидно, это не так Может кто-нибудь объяснить, почему это для меня?

Ответы [ 5 ]

6 голосов
/ 05 апреля 2010

-> это макрос, поэтому он не должен следовать правилам, которые вы ожидаете с точки зрения применения. Макрос преобразует источник до оценки форм. Попробуйте макрорасширение форм:

user> (macroexpand '(-> ["1" "2"] (partial apply str)))
(partial ["1" "2"] apply str)

Чего вы хотите достичь с помощью макроса '->?

РЕДАКТИРОВАТЬ: Обратите внимание, что:

user> ((partial apply str) ["1" "2"])
"12"
5 голосов
/ 05 апреля 2010

Тебе совсем не обязательно это делать.

(->> ["1" "2" "3"] (apply str))

Почему бы не сделать это вместо этого?

4 голосов
/ 05 апреля 2010

Первое выражение, (-> ["1" "2"] (partial apply str)), расширяется до:

(partial ["1" "2"] apply str), что в основном означает:

Создайте функцию из ["1" "2"] (которая также является функцией, поскольку векторы являются функциями индексных клавиш!) С переменными apply и str, уже предоставленными в качестве первых двух аргументов. Эта функция печатается в виде странной строки #<core$partial...>. Только когда эта функция будет вызвана, вы получите исключение IllegalArgumentException, поскольку векторы принимают только один целочисленный аргумент, а не два аргумента Var.

1 голос
/ 05 апреля 2010

Макрос -> Пропускает выражение через формы в качестве второго аргумента. В вашем случае расширение до: (partial ["1" "2"] apply str), создание функции равенства на основе вектора.

Но вы хотите вызвать функцию равенства, основанную на apply и str на резьбовом выражении и, следовательно, нужно:

(-> ["1" "2"] ((partial apply str)))

Хорошо: этот код довольно запутанный и не идиоматический Clojure.

0 голосов
/ 05 апреля 2010

Макрос -> добавляет в вашей второй версии скобки около 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 и form. Если form является последовательностью, x вставляется как второй аргумент в этом списке. В противном случае макрос помещает form и x в сам список. Это означает, что вы можете использовать пустой символ в качестве сокращения для списка, содержащего один символ.

user> (macroexpand '(-> 123 (foo)))
(foo 123)
user> (macroexpand '(-> 123 foo))
(foo 123)
...