Re:Problems with Lisp
by whacked_new on Sunday January 25, 2009 @04:02PM
(#449514)
Something I find strange about hashes in Clojure, is that you can access them using the key as a function. So instead of
({ :foo 1 :bar 2 } :foo) ;; => 1
You get the equivalent by doing (:foo { :foo 1 :bar 2 }) ;; => 1
For default values: (:baz { :foo 1 :bar 2 } 3) ;; => 3
I vaguely remember this is because keys act as functions, and hashes act as functions as well. Out of habit and similarity to other languages, I never use the key-first notation, nor can I see where it is better to use it.it's likely for usage in higher-order functions. i haven't used clojure but i assume you can do something like this:
(map :foo hashofhashes)
which would get the element :foo of every hash in hashofhashesThat's another good point, although the alternative isn't much longer:
(map #(% :foo) hashofhashes)
or if % has a chance of being nil: (map #(get % :foo) hashofhashes)Yep, the funcall semantics of symbols and keywords are to forward the symbol and key itself along with the arguments to the get function.
I do sometimes use this notation, mostly when:
- the map could be nil. (get nil :foo) and (:foo nil) will return nil, but (nil :foo) will throw an exception.
- dealing with struct-maps, where the key can effectively be seen as an accessor function. (cf structs in CL)
- (rarely) when the expression evaluating to the map is long and complex. A keyword in the function position (a) makes it clear that what follows must be a map or set and (b) you don't have to start counting parens.
Basically, maps and sets really are first-class citizens in clojure. Some of the flexibility is down to the fact that Clojure is a Lisp-1: these features are therefore hard to replicate in CL. (and yes, hash tables also bothered me somewhat in CL, altough other things probably bothered me more)