Clojure keyword arguments
Asked Answered
P

3

53

In Common Lisp you can do this:

(defun foo (bar &key baz quux)
  (list bar baz quux))

(foo 1 :quux 3 :baz 2) ; => (1 2 3)

Clojure doesn't have keyword arguments. One alternative is this:

(defn foo [bar {:keys [baz quux]}] 
  (list bar baz quux))

(foo 1 {:quux 3 :baz 2}) ; => (1 2 3)

That's too many nested brackets to have to type and read all the time. It also requires an explicit hash-map to be passed in as an argument rather than a flat list.

What's the most idiomatic Clojure equivalent of keyword arguments that doesn't look someone set off a punctuation bomb?

Presbyterian answered 4/4, 2009 at 22:39 Comment(2)
Since this question was last active keyword destructuring binding has been added to Clojure. I have provided an answer to indicate this.Chivalric
@Brian you should consider updating the accepted answer.Awry
P
39

A simple way to simulate keyword args in clojure is using hash-map on rest parameters like this:

> (defn kwtest [x & e] (:foo (apply hash-map e)))
#'user/kwtest
> (kwtest 12 :bar "ignored" :foo "returned")
"returned"

Rich Hickey provided a macro in this message from the clojure google group that gives you keyword parameters. The corresponding thread contains information about why keyword parameters are not supported by clojure. Basically to avoid the runtime overhead. Rich explains the method I've shown above in this message

Pallas answered 4/4, 2009 at 23:19 Comment(1)
See Alex Stoddard's answer; support for keyword args has been added into the parameter binding.Awry
C
102

To update this answer for Clojure 1.2 there is now full keyword arg support with defaults provided by the map forms of destructuring binding:

user> (defn foo [bar &{ :keys [baz quux] 
                        :or {baz "baz_default" quux "quux_default"}}]
         (list bar baz quux))
#'user/foo

user> (foo 1 :quux 3)
(1 "baz_default" 3)
Chivalric answered 19/10, 2010 at 14:55 Comment(1)
I think this should be promoted to be the answer?Volunteer
P
39

A simple way to simulate keyword args in clojure is using hash-map on rest parameters like this:

> (defn kwtest [x & e] (:foo (apply hash-map e)))
#'user/kwtest
> (kwtest 12 :bar "ignored" :foo "returned")
"returned"

Rich Hickey provided a macro in this message from the clojure google group that gives you keyword parameters. The corresponding thread contains information about why keyword parameters are not supported by clojure. Basically to avoid the runtime overhead. Rich explains the method I've shown above in this message

Pallas answered 4/4, 2009 at 23:19 Comment(1)
See Alex Stoddard's answer; support for keyword args has been added into the parameter binding.Awry
L
9

A recent addition to clojure.contrib.def is the defnk macro, which enables definition of functions with keyword arguments (see here).

Libertylibia answered 16/6, 2009 at 12:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.