Reputation: 10813
I have a atom with a vector value:
(def v (atom [1 2]))
I want to write a function that will return this dereferenced atom. That is, I basically want to write a function that will return the same result as this:
=> @v
[1 2]
My first take of this was something like this:
=> (let [f #(@v)]
(println (f)))
ArityException Wrong number of args (0) passed to: PersistentVector clojure.lang.AFn.throwArity (AFn.java:429)
But this of course doesn't work as dereferenced atom is not a function:
=> (@v)
ArityException Wrong number of args (0) passed to: PersistentVector clojure.lang.AFn.throwArity (AFn.java:429)
The workaround I finally ended up with is this:
=> (let [f #(vec @v)]
(println (f)))
[1 2]
nil
...but surely there must be a better way to do this that doesn't have to assume that value of atom is vector?
Upvotes: 2
Views: 876
Reputation: 17859
first of all: the reason of this error, is the expansion of lambda expression sugar syntax. You could think of it this way:
#(expression*) => (fn [] (expression*))
so, thinking this way:
#(@v) => (fn [] (@v))
and @v
in turn is expanded to (deref v)
(easily seen with macroexpansion), that lead you to this form:
(fn [] ((deref v)))
In fact you are half right with the assumed reason of the error: the result of dereference is being called as a function, but in fact it could be (as vector has functional semantics), rather it just lacks a mandatory parameter (exactly what is said in the error text).
so it should work for this: #(@v 0)
=> (fn [] ((deref v) 0))
user> (let [f #(@v 0)]
(println (f)))
1
nil
personally i would just go with a partial application, instead lambda expression to solve this:
user> (let [f (partial deref v)]
(println (f)))
[1 2]
nil
Upvotes: 1
Reputation: 13294
None of the existing answers give the two simplest, most concise solutions, so here they are. As stated by @Stefan, you want something equivalent to this function:
(fn [] (deref v))
However, this usage of deref
is exactly the use case that the @
reader macro is meant to simplify:
(fn [] @v)
Or, since (deref v)
is a function call, you could instead use the #()
reader macro:
#(deref v)
The main point here is that you can't use both @
and #()
together in this case. But that doesn't mean you can't or shouldn't use one of them.
Upvotes: 2
Reputation: 34800
I want to write a function that will return this dereferenced atom
(def v (atom [1 2]))
(defn foo [] @v)
(foo) ;;=> [1 2]
Upvotes: 1
Reputation: 1665
Sometimes it is better to leave reader constructs like #
and @
out and just go with the functions (or macros and special forms):
user> (def v (atom [1 2]))
#'user/v
user> (let [f (fn [] (deref v))] (f))
[1 2]
I take it, that your example is a very simplified version of what you really want to do. If not, deref
may be just the function you are looking for.
Upvotes: 1