Function for applying to a user with a various number of data fields

房东的猫 提交于 2019-12-02 08:43:07

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:

(let [user {:name "Alan" :surname "Smith" :alias "Mike"}]
    (apply
        (fn [& args]
            (let [args (into {} args)]
                (println (str "I am " (:name args) " " (:surname args) "."))))
        user))

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), because apply 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

(def user {:name "Alan" :surname "Smith" :alias "Mike"})
(apply
  (fn [& args]
    (prn 'ARGS args)  ;; lets see what is actually in args
    (println (str "I am " (:name args) " " (:surname args) ".")))
  user)
;; -> ARGS ([:name "Alan"] [:surname "Smith"] [:alias "Mike"])
;; -> I am  .

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):

(def user {:name "Alan" :surname "Smith" :alias "Mike"})
(apply
  (fn [args]
    (prn 'ARGS args) 
    (println (str "I am " (:name args) " " (:surname args) ".")))
  [user])

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":

(def user {:name "Alan" :surname "Smith" :alias "Mike"})
(apply
  (fn [& args]
    (let [{:keys [name surname alias]} (into {} args)]
      (println (str "I am " name " " surname "." (when alias (str " But call me " alias "!"))))))
  user)

I believe you intended to do something like this:

(def user  {:name "Alan" :surname "Smith" :alias "Mike"})
(def user2 {:name "Jane" :surname "Smith"})

(defn fn-1
  [item]
   (println (str "I am " (:name item) " " (:surname item) ".")) )
(defn fn-2
  [item]
  (println (str "My sister is " (:name item) " " (:surname item) ".")))

  (fn-1 user)
  (fn-2 user2)

with result:

I am Alan Smith.
My sister is Jane Smith.

One has to wrap a user object or the map by a list.

(ns observer.core)
(defrecord Person [name balance])
(def user (Person. "Alan" 150.34))
(def user2 {:name "Adam" :balance 629.74})
(def observers (atom #{}))
(swap! observers conj (fn [l] (println (str "2. " (:name l)))))
(swap! observers conj (fn [l] (println (str "1. " (:balance l)))))
(println "user")
(vec (map #(apply % (list user)) @observers))
(println "\nuser2")
(vec (map #(apply % (list user2)) @observers))

Output

user
1. 150.34
2. Alan

user2
1. 629.74
2. Adam
observer.core>
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!