Reputation: 973
If I evaluate:
(:content {:foo "bar" :biz "baf" :content ("Happy Happy Joy Joy")})
I get:
java.lang.String cannot be cast to clojure.lang.IFn
If I wanted the "Happy Happy Joy Joy"
string, how do I get it?
In my case, the hash-map is what I have to work with... I didn't create the string value inside a list. I understand clojure considers it a function as it's in the calling position.
Upvotes: 1
Views: 84
Reputation: 29958
The other answers did not fully clarify the effect of quote
. Please see this code:
(ns tst.demo.core
(:use tupelo.test)
(:require
[tupelo.core :as t] ))
; Note:
; (def data {:foo "bar" :biz "baf" :content ("Happy Happy Joy Joy")})
; => exception
(def data-1 '{:foo "bar" :biz "baf" :content ("Happy Happy Joy Joy")})
(def data-2 {:foo "bar" :biz "baf" :content '("Happy Happy Joy Joy")})
(def data-3 (quote {:foo "bar" :biz "baf" :content ("Happy Happy Joy Joy")}))
(dotest
(is= data-1 data-2 data-3)
(is= "Happy Happy Joy Joy" (first (:content data-1)))
(is= "Happy Happy Joy Joy" (first (:content data-2)))
(is= "Happy Happy Joy Joy" (first (:content data-3))))
So, data-1
shows we can quote the entire expression at the outer level, and data-2
shows we can also quote each list expression (stuff in parens) to suppress the "function call" interpretation of a "list" type in Clojure.
data-3
shows that the single-quote char '
is just short for the special form (quote ...)
in Clojure.
Once you get the data literal form right, we see that data-1
and data-2
and data-3
actually result in identical data structures after being processed by the reader.
The last 3 tests show the proper syntax for extracting the string of interest from any of the 3 data structures.
P.S. The testing stuff dotest
and is=
is from the Tupelo library.
Upvotes: 0
Reputation: 6509
What is typed that has to include quote ('
) literals to prevent the error message you are getting will be different from what is being returned from a function that does not have to have quotes in it. So just play with it a bit for the real (non REPL) case.
(def x '(:content {:foo "bar" :biz "baf" :content '("Happy Happy Joy Joy")}))
(-> x second :content second first)
;;=> "Happy Happy Joy Joy"
For the real case (-> x second :content first)
might be what you want, where of course x
is the function call.
If as you say it is only the hash-map (m
) you are concerned with then (-> m :content first)
should do the trick.
One solution to the mismatch between the REPL and reality is to just use vectors instead of lists:
(def x [:content {:foo "bar" :biz "baf" :content ["Happy Happy Joy Joy"]}])
Here (-> x second :content first)
will indeed work.
Upvotes: 1
Reputation: 16194
If you're defining that list literally in your code, you'll need to "quote" it so that it isn't evaluated as a function:
user=> (:content {:foo "bar" :biz "baf" :content '("Happy Happy Joy Joy")})
("Happy Happy Joy Joy")
The only difference here is the '
character before the opening list parenthesis. You could also use the list
function.
If you want just the first item in the :content
list, you can then use first
:
user=> (first (:content {:foo "bar" :biz "baf" :content '("Happy Happy Joy Joy")}))
"Happy Happy Joy Joy"
Upvotes: 1