#macros #map #clojure
#макросы #словарь #clojure
Вопрос:
Как мы должны знать, Clojure map
может быть применен к последовательности:
(map #(* %1 %1) [1 2 3]) ; (1)
..или для нескольких, таким образом:
(map vector [0 1] [2 1]) ; (2)
;=> ([0 2] [1 1])
Теперь я хочу получить тот же результат, что и (2), но у меня есть аргументы, хранящиеся внутри последовательности. Другими словами, следующее не дает желаемого результата:
(map vector [[0 1] [2 1]]) ; (3)
;=> ([[0 1]] [[2 1]])
Итак, я написал этот простой макрос, где umap расшифровывается как «unsplice map».:
(defmacro umap [fun args-list]
"umap stands for unspliced map.
Let args-list be a list of args [a1 a2 ... an].
umap is the same of (map fun a1 a2 .. an)"
`(map ~fun ~@args-list))
Очевидно, что это работает как шарм:
(umap vector [[0 1] [2 1]]) ; (4)
;=> ([0 2] [1 1])
Итак, вот мой вопрос: изобретаю ли я колесо?
Есть ли другой способ сделать то же самое, что и (4)?
Пока и заранее спасибо,
Альфредо
Ответ №1:
apply
распаковывает все элементы в последовательности в конце списка аргументов.
user> (apply map vector [[0 1] [2 1]])
([0 2] [1 1])
Комментарии:
1. Спасибо, я был уверен, что изобретаю колесо заново 🙂
Ответ №2:
Совсем не очевидно, что ваш umap
работает как шарм. На самом деле это сработает только в том случае, если во время компиляции у вас есть вектор аргументов в виде литерала — а это именно то время, когда вы в любом случае могли бы передать несколько аргументов map
!
user> (umap vector [[1 2] [1 2]])
([1 1] [2 2])
user> (let [args [[1 2] [1 2]]]
(umap vector args))
java.lang.IllegalArgumentException: Don't know how to create ISeq from: clojure.lang.Symbol
[Thrown class java.lang.RuntimeException]
Макрос имеет доступ только к символу args
, потому что он выполняется во время компиляции и не может объединить его для использования map. Правильный ответ — использовать apply
, который обрабатывает свой последний аргумент как последовательность и объединяет его в серию дополнительных аргументов для данной функции:
user> (let [args [[1 2] [1 2]]]
(apply map vector args))
([1 1] [2 2])
Комментарии:
1. Спасибо, амаллой, твои ответы всегда полезны!
Ответ №3:
Я что-то упускаю, или mapcat подходит для ваших нужд?
Комментарии:
1. Вы, должно быть, чего-то не хватает, но я не уверен, чего.
mapcat
это ни на йоту не приближает его к решению его проблемы.2. Ах, ладно. Кажется, теперь я понимаю, чего мне не хватало.