Reputation: 355
(defrecord Sample (x y))
(def check (Sample. 1 2))
(:x check) ;returns 1
If I receive (:x check) as an argument to a function, is there a way to access check? Or, in other words, return
#:user.Sample{:x 1, :y 2}
Upvotes: 2
Views: 135
Reputation: 2600
As Óscar described, (:x check)
won't work because its result is 1
, and '(:x check)
won't work because its result is a list containing the keyword :x
and the symbol check
.
However, instead of using quote you could use the list
function:
(defn receiver [arg]
(map class arg))
;; With a quoted list it receives the symbol `check` rather
;; than the Sample record
(receiver '(:x check))
;=> (clojure.lang.Keyword clojure.lang.Symbol)
;; But this way it does receive the Sample
(receiver (list :x check))
;=> (clojure.lang.Keyword user.Sample)
And (list :x check)
can be evaluated:
(eval (list :x check))
;=> 1
(defn receiver [arg]
(str "received " arg "; eval'd to: " (eval arg)))
(receiver (list :x check))
;=> "received (:x #user.Sample{:x 1, :y 2}); eval'd to: 1"
The reason that quote
and list
behave so differently is that quote
doesn't evaluate it's argument. And, when a list is quoted, that effect is recursive: none of the items in the list are evaluated either.
There's another type of quote, called syntax-quote or backquote (and described on the Clojure.org page about the reader) which allows you to selectively un-quote (i.e. evaluate) items.
(require '[clojure.pprint])
(let [n 1
x :x
c check]
(clojure.pprint/pprint
(vector `(n x c)
`(~n x c)
`(~n ~x c)
`(~n ~x ~c))))
Prints:
[(user/n user/x user/c)
(1 user/x user/c)
(1 :x user/c)
(1 :x {:x 1, :y 2})]
And, actually, I lied a little bit. You could in fact use '(:x check)
in this particular case. resolve
will return the Var
associated with a symbol, and deref
(or its @
reader macro) will get you the Var's value.
(resolve 'check)
;=> #'user/check
(deref (resolve 'check))
;=> #user.Sample{:x 1, :y 2}
(defn resolve-and-deref-symbols [form]
(map (fn [x] (if (symbol? x)
@(resolve x)
x))
form))
(defn receiver [arg]
(str "received " arg "; eval'd to: " (eval (resolve-and-deref-symbols arg))))
(receiver '(:x check))
;=> "received (:x check); eval'd to: 1"
I didn't mention it straight-away because, while it works easily enough in this example, it's not at all appropriate for the general case. (For instance, it won't work with locals, and handling namespaces and nested data structure would be painful).
Upvotes: 2
Reputation: 236004
No, if a function is passed (:x check)
as parameter then the value was already evaluated before entering the function, you'll just receive a 1
as value, and you can't retrieve the record it came from.
If you need the record inside the function, why don't you pass check
as parameter?
Upvotes: 4