Clojure - именованные аргументы - PullRequest
76 голосов
/ 26 июля 2010

Есть ли у Clojure именованные аргументы? Если да, не могли бы вы привести небольшой пример?

Ответы [ 4 ]

115 голосов
/ 26 июля 2010

В 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.

33 голосов
/ 27 июля 2010

В дополнение к отличному ответу Рэйнса, есть также макрос в 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]
1 голос
/ 14 декабря 2018

Начиная с Clojure версии 1.8, поддержка ключевых слов по-прежнему выглядит немного meh .

Вы можете указать аргументы ключевых слов, например:

(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))
0 голосов
/ 26 июля 2010

Возможно, вы имеете в виду именованные параметры ?Они не доступны напрямую, но вы можете использовать этот векторный подход , если хотите, что может дать вам то, что вы хотите.о том, как сделать это с помощью деструктуризации.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...