I'm taking my first steps with Clojure. Otherwise, I'm somewhat competent with JavaScript, Python, Java, and a little C.
I was reading this artical that describes destructuring vectors and maps. E.g.
=> (def point [0 0])
=> (let [[x y] point]
=> (println "the coordinates are:" x y))
the coordinates are: 0 0
but I'm having a difficult time understanding keywords. At first glance, they seem really simple, as they just evaluate to themselves:
=> :test
:test
But they seem to be used is so many different ways and I don't understand how to think about them. E.g., you can also do stuff like this:
=> (defn full-name [& {first :first last :last}]
=> (println first last))
=> (full-name :first "Tom" :last "Brennan")
Tom Brennan
nil
This doesn't seem intuitive to me. I would have guessed the arguments should have been something more like:
(full-name {:first "Tom" :last "Brennan"})
because it looks like in the function definition that you're saying "no required arguments, but a variable number of arguments comes in the form of a single map". But it seems more like you're saying "no required arguments, but a variable number of arguments comes which should be a list of alternating keywords and values... ?" I'm not really sure how to wrap my brain around this.
Also, things like this confuse me too:
=> (def population {:humans 5 :zombies 1000})
=> (:zombies population)
1000
=> (population :zombies)
1000
How do maps and keywords suddenly become functions?
If I could get some clarification on the use of keywords in these two examples, that would be really helpful.
Update I've also seen https://stackoverflow.com/questions/3337888/clojure-named-arguments and while the accepted answer is a great demonstration of how to use keywords with destructuring and named arguments, I'm really looking more for understanding how to think about them--why the language is designed this way and how I can best internalize their use.
1 Answer 1
the & in (defn full-name [& {first :first last :last}] indicates that all the remaining arguments should be gathered into a single collection. the map destructuring form following the & then takes the map created by the & apart again.
(defn full-name [& {first :first last :last}]...)
(full-name :first "Tom" :last "Brennan")
without the & becomes
(defn full-name [{first :first last :last}]...)
(full-name {:first "Tom" :last "Brennan"})
for your other question: symbols and keywords implement the function interface so they can be called just like any other Clojure function. when called as a function they look themselves up in their argument which they expect to be a map (or something implementing the appropriate interface)