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

末鹿安然 提交于 2019-12-02 22:07:13

问题


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?


回答1:


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}).




回答2:


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)



回答3:


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.



回答4:


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>


来源:https://stackoverflow.com/questions/55705759/function-for-applying-to-a-user-with-a-various-number-of-data-fields

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