Clojure - named arguments

Does Clojure have named arguments? If so, can you provide a small example?

+75
clojure
Jul 26 '10 at 18:40
source share
4 answers

In Clojure 1.2, you can destroy the rest argument just as if you had destroyed the map. This means that you can use 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"} 

All you can do while destructuring a Clojure map can be done in the function's argument list, as shown above. Including use: or to define default values ​​for such arguments:

 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. In addition, 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 it works the same overall.

And you can also have positional arguments that come before the keyword arguments:

 user> (defn blah [xy & {:keys [key1 key2 key3] :or {key3 10}}] (str xy key1 key2 key3)) #'user/blah user> (blah "x" "Y" :key1 "Hai" :key2 " there") "xYHai there10" 

They are not optional and must be provided.

In fact, you can destroy the rest argument, like 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 such things even in Clojure 1.1. However, file-style destructuring for keyword arguments appeared only in 1.2.

+114
Jul 26 2018-10-18T00:
source share

In addition to Raines' excellent answer, a macro in clojure -contrib that makes life easier:

 user => (use '[clojure.contrib.def: only [defnk]])
 nil
 user => (defnk foo [ab: c 8: d 9] 
          [abcd])
 # '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]
+33
Jul 26 '10 at 20:41
source share

Perhaps you mean named parameters? They are not available, but you can use this approach for vectors if you want, which can give you what you want.

RosettaCode has a more detailed explanation of how to do this using destructuring.

0
Jul 26 '10 at 18:44
source share

Starting with Clojure version 1.8, keyword support still doesn't look very good.

You can specify key arguments like this:

 (defn myfn1 "Specifying keyword arguments without default values" [& {:keys [arg1 arg2]}] (list arg1 arg2)) 

Examples of calling this:

 (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 key 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) 

Each part of each language has its pros and cons, but for comparison, you can do the same 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)) 
0
Dec 14 '18 at 6:23
source share



All Articles