Does Clojure have named arguments? If so, can you please provide a small example of it?
4 Answers
In Clojure 1.2, you can destructure the rest
argument just like you would destructure a map. This means you can do named non-positional keyword arguments. Here is an example:
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"}
Anything you can do while destructuring a Clojure map can be done in a function's argument list as shown above. Including using :or to define defaults for the arguments like this:
user> (defn blah [& {:keys [key1 key2 key3] :or {key3 10}}] (str key1 key2 key3))
#'user/blah
user> (blah :key1 "Hai" :key2 " there")
"Hai there10"
But this is in Clojure 1.2. Alternatively, in older versions, you can do this to simulate the same thing:
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"
and that works generally the same way.
And you can also have positional arguments that come before the keyword arguments:
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"
These are not optional and have to be provided.
You can actually destructure the rest
argument like you would any Clojure collection.
user> (defn blah [& [one two & more]] (str one two "and the rest: " more))
#'user/blah
user> (blah 1 2 "ressssssst")
"12and the rest: (\"ressssssst\")"
You can do this sort of thing even in Clojure 1.1. The map-style destructuring for keyword arguments only came in 1.2 though.

- 31,473
- 17
- 86
- 101
In addition to Raynes' excellent answer, there is also a macro in clojure-contrib that makes life easier:
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]

- 7,805
- 28
- 31
-
7I forgot to mention that! I was all caught up in showing the 10 thousand ways Clojure can destructure stuff. :p – Rayne Jul 26 '10 at 22:11
-
1clojure-contrib is deprecated, and I couldn't find a current alternative. Any ideas? – Lstor Jul 21 '14 at 15:03
-
2@Lstor: check out [defnk](https://github.com/Prismatic/plumbing/blob/7ae0e85e4921325b3c41ef035c798c29563736dd/src/plumbing/core.cljx#L470) in [prismatic/plumbing](https://github.com/Prismatic/plumbing) – Ian Apr 16 '15 at 16:00
As of Clojure version 1.8, keyword support still seems a bit meh.
You can specify keyword arguments like this:
(defn myfn1
"Specifying keyword arguments without default values"
[& {:keys [arg1 arg2]}]
(list arg1 arg2))
Examples of calling it:
(myfn1 :arg1 23 :arg2 45) --> evaluates to (23 45)
(myfn1 :arg1 22) --> evaluates to (22 nil)
If you want to specify default values for these keyword arguments:
(defn myfn2
"Another version, this time with default values specified"
[& {:keys [arg1 arg2] :or {arg1 45 arg2 55}}]
(list arg1 arg2))
This does the expected thing in the second case:
(myfn2 :arg1 22) --> evaluates to (22 55)
There are pros and cons to each part of each language, but just for comparison, this is how you would do the same stuff in 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))

- 5,064
- 6
- 31
- 37
Do you perhaps mean named parameters? These aren't directly available, but you can use this vectors approach (web archive link) if you like, which may give you what you want. Copy of that example:
Technically, in Clojure this is not really "named params" but how Clojure destructures maps passed into the parameter vector.
user> (defn a [{b :b c :c}] (- b c)) #'user/a user> (a {:c 5 :b 11}) 6
At RosettaCode there's a deeper explanation on how to do this using destructuring.
Quote (in case of linkrot):
Clojure doesn't have built-in support for named or keyword arguments, but you can use destructuring to achieve a similar effect.
(defn foo [& opts] (let [opts (merge {:bar 1 :baz 2} (apply hash-map opts)) {:keys [bar baz]} opts] [bar baz]))
Clojure 1.2 supports destructuring of trailing arguments as a map:
(defn foo [& {:keys [bar baz] :or {bar 1, baz 2}}] [bar baz])
You can also use defnk from
clojure.contrib.def
, which is a macro that works similarly.(use 'clojure.contrib.def) (defnk foo [:bar 1 :baz 2] [bar baz])
Sample output for all variants:
user> (foo :baz 123) [1 123]
user> (foo :bar 456) [456 2]

- 56,041
- 24
- 146
- 247
-
3@Abel Can you share the examples you link to? (They have a way of changing or getting out of date). – David J. Feb 24 '14 at 16:03
-
-
1@Terbiy and david you are right, I should have done that. Usually I do add inline examples. Not sure what I was thinking over a decade ago lol. Anyway, thanks to the wayback machine, it is all still there. Copied for posterity. – Abel Aug 11 '23 at 10:08