How clojure map and keyword can be a function
In clojure, you can use the map data structure or keyword as a function to find the map.
(let [m {:foo "bar"}]
(get m :foo) ; -> "bar"
(:foo m) ; -> "bar"
(m :foo)) ; -> "bar"
All of these expressions return the value "bar". Implementation wisely, how can you use a map or a keyword as a function? Is this a special case built into the clojure interpreter, or is it something I could recreate with the language? What's really going on under the hood?
+2
source to share
2 answers
All this is done with regular java under the hood.
There is an iFn interface that can implement anything in Clojure that wants to be called as a function. It depends on this thing to decide what to do when called.
- Keywords are selected to search for in the collection passed as the first argument.
- Maps are chosen to search for an argument passed as a key in itself.
- Symbols also appear on their own in the collection. Very similar to keywords.
- Vars makes a function call to whatever function they contain using whatever arguments they passed. And they use the same interface for this.
+4
source to share
Just to show you how this is possible in any language that has first class functions - the JavaScript example below; run it to see the results!
const map = x => a =>
a === undefined ? x : a(map(x))
const get = m => a =>
a(m)
const accessor = k => m =>
m()[k]
// make accessor
const foo = accessor('foo')
// make map
let m = map({foo: 'bar'})
// test expressions
// get applied to map and accessor:
console.log(get (m) (foo)) // bar
// accessor applied to map:
console.log(foo (m)) // bar
// map applied to accessor:
console.log(m (foo)) // bar
+2
source to share