Clojure применение уничтожения карт и ключевых слов

Рассмотрим функцию со следующей сигнатурой:

(defn make-widget [& {:keys [x y] :or {x 10 y 20}}]
 ...)

Каков наилучший способ передать карту функции, например:

(make-widget {:x 100})

или

(make-widget {:y 200 :x 0})

То, что я сейчас думал, это через vec, flatten и apply например:

(apply make-widget (flatten (vec ({:x 100}))

Я твердо верю, что есть лучший способ сделать это. Можете ли вы подумать об этом?

Ответ 1

Я не могу придумать более элегантный способ, хотя мне кажется, что он должен быть одним (например, для варианта с картой apply).

Использование flatten имеет проблемы, помимо того, что они не очень элегантны. Если значения вашей карты являются коллекциями, flatten будет работать рекурсивно на них, так что вещи могут быть полностью перепутаны. Этот альтернативный вариант позволяет избежать этой проблемы:

(apply make-widget (apply concat {:x 100}))

Ответ 2

Существует также известный (не изобретенный мной хотя бы), функция "mapply":

(defn mapply [f & args] (apply f (apply concat (butlast args) (last args))))

который может быть применен как

(mapply your-function {:your "map"})

Что касается того, почему эта языковая функция отсутствует в ядре Clojure, будучи реализована более изящно и элегантно, никто не сможет дать мне ясный ответ.

UPDATE

После того, как я потратил много времени на программирование в Clojure, я лично предпочитаю воздерживаться от создания функций, которые принимают {} как vararg. Хотя сначала это может показаться привлекательным, на самом деле опыт доказывает, что передача явного {} всегда лучше по многим причинам.

Ответ 3

Вы можете использовать:

(apply make-widget (mapcat identity {:x 200 :y 0}))