The question was born when I was practicing an Observer topic in a tutorial I am trying to apply the function to the user but cannot use user's data fields like name, surname.
Let's say that the user may have various number of data fields so we must use & args
argument. My code that does not work:
(ns observer.core)
(def user {:name "Alan" :surname "Smith" :alias "Mike"})
(def user2 {:name "Jane" :surname "Smith"})
(apply
(fn [& args] (println (str "I am " (:name args) " " (:surname args) ".")))
user)
(apply
(fn [& args] (println (str "My sister is " (:name args) " " (:surname args) ".")))
user2)
The output:
I am .
My sister is .
observer.core>
How to fix it regarding that the apply
function must be used?
One has to wrap a user object or the map by a list.
Output
apply
converts a map to a seq, i.e.{:name "Alan" :surname "Smith" :alias "Mike"}
becomes([:name "Alan"] [:surname "Smith"] [:alias "Mike"])
You could put it back into a map, if that is what you need:
but this looks a bit of a stretch to me. I believe the solution could have been better if I knew how this function is supposed to be used.
Usually there are two types of functions:
(fn :text "some" :row 25)
and(fn {:text "some" :row 25})
.In the spirit of learning:
Check out Clojure - Cheatsheet. 10 years with Clojure, and I still use it daily.
(apply some-func (list x y z))
becomes(some-func x y z)
, becauseapply
assumes that the second argument is a list (which it then unpacks).And what you are currently doing is collecting all the arguments back into a list called
args
And the outut is as @akond says.
You could, of course, put 'user' in a vector (or list), but then don't use '&' to collect everything back into a list, (which you would then have to pick stuff out of again):
That would give you the output you expected. But this is a bit strange, perhaps, but certainly viable if you must use
apply
and you can control the "list" part of the argument.So, @akond's solution is simple and clean.
And augmenting it with Clojure "destructing":
I believe you intended to do something like this:
with result: