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