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.
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 ClassCastException
s as the sequence generates Vector
elements, not MapEntry
elements.
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})
(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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With