Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What does clojure 'val' return this value?

Tags:

clojure

I'm just starting to learn clojure and have been reading some simple examples and then doing my best to rtfm for concepts.

However I'm a bit confused by what val is doing in the example below. This has been taken from the Clojure doc examples for val.

(first {:one :two}) ;; => [:one :two]

Here, a hash-map with a key of :one and a value of :two is being passed to first. Behind the scenes, Clojure converts this hash-map to a sequence of vectors. Since there is only one vector in this sequence, it returns [:one :two].

(val (first {:one :two})) ;; => :two
(val [:one :two]) ;; => ClassCastException clojure.lang.PersistentVector cannot be cast to java.util.Map$Entry
(val {:one :two}) ;; => ClassCastException clojure.lang.PersistentArrayMap cannot be cast to java.util.Map$Entry

If I try to call val on a (I think) a hash-map (I realize it's actually a "persistent array map"), I get the exception as seen above.

I'm also confused by the following:

(first {:one :two}) ;; # => [:one :two]  (this is a vector right?)
(val [:one :two]) ;; # => ClassCastException (why doesn't this give back the same result as the example above?)

Why can't I just plug the result of (first {:one :two}) into val and get the same result?


Additionally, another example listed on the page is the following:

(map val {:a 1 :b 2}) ;; => (1 2)

Here's how I read the line. Take the array-map {:a 1 :b 2}. For each key-value pair, call val on the pair to return the value. Return a sequence from the resulting calls to map. Is this the correct way to read the problem?

As always, thanks for any and all help.

like image 675
Kurt Mueller Avatar asked Jun 11 '15 21:06

Kurt Mueller


3 Answers

a sequence of a map produces MapEntry values as you've noted, which look like and can be compared with vectors

user=> (= (first {:a 1 :b 2}) [:a 1])
true

but aren't the same class

user=> (= (class (first {:a 1 :b 2})) (class [:a 1]))
false

So although the output on the repl of (first {:a 1}) looks like a vector, it isn't, it's a MapEntry, so it can be passed to val, but the vector [:a 1] cannot, hence the class cast exception.

Your reading of what map is doing is correct at a high level, a little more specific might be "For each entry in the sequence from {:a 1 :b 2} (which are MapEntry values) call the function val on each item (a MapEntry), and generate a sequence from the results".

This will explain why something like

user=> (map val '([:a 1] [:b 2]))

will cause the same ClassCastExceptions as the sequence generates Vector elements, not MapEntry elements.

like image 189
Mark Fisher Avatar answered Sep 20 '22 02:09

Mark Fisher


val returns value of a map entry, not a map.

(first {:one :two}) return the first map entry (although it appears to be just a vec)

(map val {:one :two}) return the value of every entry, and is equivalent to (vals {:one :two})

like image 37
Fabricator Avatar answered Sep 20 '22 02:09

Fabricator


(first {:one :two}) ;; # => [:one :two]  (this is a vector right? No, it's not.)

[:one :two] in this case is a MapEntry, not a vector.

like image 44
Nick Avatar answered Sep 20 '22 02:09

Nick