Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does using keywords or symbols as functions to lookup values from maps work?

Tags:

clojure

Quoting from Joy of Clojure, section 4.3.1--

Because keywords are self-evaluating and provide fast equality checks, they're almost always used in the context of map keys. An equally important reason to use keywords as map keys is that they can be used as functions, taking a map as an argument, to perform value lookups:

(def population {:zombies 2700, :humans 9})
(:zombies population)
;=> 2700
(println (/ (:zombies population)
(:humans population))
"zombies per capita")
; 300 zombies per capita

It is not apparent to me what is going on here. Somehow (:zombies population) has to get transformed into (get population :zombies), right? How exactly does this work? The keyword evaluates to itself, not to a function. Does the reader look out for cases where the first thing in a list is a keyword, and add get and move the keyword to the end of the list?

like image 604
Nathan Hughes Avatar asked Aug 02 '11 16:08

Nathan Hughes


3 Answers

Citation from official documentation:

Keywords implement IFn for invoke() of one argument (a map) with an optional second argument (a default value). For example (:mykey my-hash-map :none) means the same as (get my-hash-map :mykey :none). See get.

And Clojure can call keyword as function, because it implements same interface as function. The same is for symbols...

like image 63
Alex Ott Avatar answered Oct 29 '22 17:10

Alex Ott


Keywords are functions, in every way. There is no reader magic involved, as you will see if you try (let [m {:humans 100}, k :humans] (k m)). I hope you'll agree there's no way the reader could turn this into a get (the compiler could, but you can pretend that I've made the value of k depend on an if expression that the compiler can't predict, such as user input).

Because Clojure's core data types are interfaces, and Java objects can implement many interfaces, a piece of data can have multiple types. Is it a keyword? Yes. Is it a function? Also yes:

user> (keyword? :k)
true
user> (ifn? :k)
true
user> (.invoke :k {:k 1})
1
like image 29
amalloy Avatar answered Oct 29 '22 15:10

amalloy


Keywords implement IFn,

https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Keyword.java

and its invoke method handles calling get.

like image 6
Hamza Yerlikaya Avatar answered Oct 29 '22 15:10

Hamza Yerlikaya