Имеет ли Clojure именованные аргументы? Если да, можете ли вы предоставить небольшой пример?
Clojure - названные аргументы
Ответ 1
В Clojure 1.2 вы можете разрушить аргумент rest
так же, как если бы вы разрушили карту. Это означает, что вы можете использовать именованные непозиционные аргументы ключевых слов. Вот пример:
user> (defn blah [& {:keys [key1 key2 key3]}] (str key1 key2 key3))
#'user/blah
user> (blah :key1 "Hai" :key2 " there" :key3 10)
"Hai there10"
user> (blah :key1 "Hai" :key2 " there")
"Hai there"
user> (defn blah [& {:keys [key1 key2 key3] :as everything}] everything)
#'user/blah
user> (blah :key1 "Hai" :key2 " there")
{:key2 " there", :key1 "Hai"}
Все, что вы можете сделать, пока деструктурирование карты Clojure может быть выполнено в списке аргументов функции, как показано выше. Включая использование: или для определения значений по умолчанию для таких аргументов:
user> (defn blah [& {:keys [key1 key2 key3] :or {key3 10}}] (str key1 key2 key3))
#'user/blah
user> (blah :key1 "Hai" :key2 " there")
"Hai there10"
Но это в Clojure 1.2. Кроме того, в более старых версиях вы можете сделать это, чтобы имитировать одно и то же:
user> (defn blah [& rest] (let [{:keys [key1 key2 key3] :or {key3 10}} (apply hash-map rest)] (str key1 key2 key3)))
#'user/blah
user> (blah :key1 "Hai" :key2 " there")
"Hai there10"
и это работает в целом одинаково.
И вы также можете иметь позиционные аргументы, которые идут перед аргументами ключевого слова:
user> (defn blah [x y & {:keys [key1 key2 key3] :or {key3 10}}] (str x y key1 key2 key3))
#'user/blah
user> (blah "x" "Y" :key1 "Hai" :key2 " there")
"xYHai there10"
Они не являются необязательными и должны быть предоставлены.
Фактически вы можете разрушить аргумент rest
, как и любую коллекцию Clojure.
user> (defn blah [& [one two & more]] (str one two "and the rest: " more))
#'user/blah
user> (blah 1 2 "ressssssst")
"12and the rest: (\"ressssssst\")"
Вы можете делать такие вещи даже в Clojure 1.1. Однако деструктуризация в стиле файла для аргументов ключевого слова появилась только в 1.2.
Ответ 2
В дополнение к отличному ответу Рейнса, макрос в clojure -contrib, который облегчает жизнь:
user=> (use '[clojure.contrib.def :only [defnk]]) nil user=> (defnk foo [a b :c 8 :d 9] [a b c d]) #'user/foo user=> (foo 1 2) [1 2 8 9] user=> (foo 1 2 3) java.lang.IllegalArgumentException: No value supplied for key: 3 (NO_SOURCE_FILE:0) user=> (foo 1 2 :c 3) [1 2 3 9]
Ответ 3
Возможно, вы имеете в виду именованные параметры? Они недоступны, но вы можете использовать этот подход для векторов, если хотите, что может дать вам то, что вы хотите.
В RosettaCode есть более подробное объяснение того, как это сделать, используя деструктурирование.
Ответ 4
Начиная с Clojure версии 1.8, поддержка ключевых слов по-прежнему выглядит не очень хорошо.
Вы можете указать ключевые аргументы, как это:
(defn myfn1
"Specifying keyword arguments without default values"
[& {:keys [arg1 arg2]}]
(list arg1 arg2))
Примеры вызова этого:
(myfn1 :arg1 23 :arg2 45) --> evaluates to (23 45)
(myfn1 :arg1 22) --> evaluates to (22 nil)
Если вы хотите указать значения по умолчанию для этих ключевых аргументов:
(defn myfn2
"Another version, this time with default values specified"
[& {:keys [arg1 arg2] :or {arg1 45 arg2 55}}]
(list arg1 arg2))
Это делает ожидаемую вещь во втором случае:
(myfn2 :arg1 22) --> evaluates to (22 55)
У каждой части каждого языка есть свои плюсы и минусы, но для сравнения, вы можете сделать то же самое в Common Lisp:
(defun myfn3
(&key arg1 arg2)
"Look Ma, keyword args!"
(list arg1 arg2))
(defun myfn4
(&key (arg1 45) (arg2 55))
"Once again, with default values"
(list arg1 arg2))