Clojure更改绑定本地';s值取决于条件

Clojure更改绑定本地';s值取决于条件,clojure,let,Clojure,Let,根据以下情况,idomatic方法是什么?这里我根据一些条件改变x的值 (defn person-story [person] (let [x (str "My name is " (:firstname person) " " (:lastname person) "." ) x (if (:showaddress person) (str x " I live in " (:address person) ".") x) x (if (:showage person)

根据以下情况,idomatic方法是什么?这里我根据一些条件改变x的值

(defn person-story
 [person]
  (let [x (str "My name is " (:firstname person) " " (:lastname person) "." )
    x (if (:showaddress person) (str x " I live in " (:address person) ".") x)
    x (if (:showage person) (str x " I am " (:age person) " yrs old. ") x)
    x (if (seq (:hobby person)) (str x " I like " (clojure.string/join ", " (:hobby person)) ".") x)]
x))

(person-story {:firstname "John" :lastname "Doe" :age 45 :showage false :address "67 Circe Ave" :showaddress true :hobby ["movie" "music" "money"]})
这将产生:

"My name is John Doe. I live in 67 Circe Ave. I like movie, music, money."
如果我用java来做,我会做一些类似的事情:

    StringBuilder sb = new StringBuilder("My name is ");
    sb.append(person.get("firstname")).append(" ");
    sb.append(person.get("lastname")).append(" ");
    if (showaddress) sb.append("I live in ").append(person.get("address")).append(" ");
    if (showage) sb.append("I am ").append(person.get("age")).append(" yrs old. ");
    List<String> hobbies = person.get("hobby");
    if ( hobbies != null && !hobbies.isEmpty()) sb.append("I like "). append(StringUtils.join(hobbies, ", "));
    return sb.toString()
输出:

"My name is John Doe. I live in Universal Studios. I am 50 yrs old. I like movies, music, money."
"My name is John Doe. I live in Universal Studios. I like movies, music, money"
xsc的方法:

(defn person-story2 [person]
  (let [tests [[:showaddress #(format " I live in %s." (:address %))]
               [:showage #(format " I am %s yrs old." (:age %))]
               [(comp seq :hobbies) #(format " I like %s." (clojure.string/join ", " (:hobbies %)))]]]
    (apply str (format "My name is %s %s." (:firstname person) (:lastname person))
           (for [[test f] tests
                 :when (test person)]
             (f person)))))


(person-story2 {:firstname "John" :lastname "Doe" :showage true :age 50  :showaddress true :address "Universal Studios" :hobbies ["movies" "music" "money"]})
(defn person-story 
  [{:keys [firstname lastname address showaddress age showage hobbies] :as person}]
  (cond-> 
   (str "My name is " firstname " " lastname ". ")
   showaddress (str "I live in " address ". ")
   showage (str "I am " age " yrs old. ")
   (seq hobbies) (str "I like " (clojure.string/join ", " hobbies))))

(person-story {:firstname "John" :lastname "Doe" :showage false :age 50 :address "Universal Studios" :showaddress true :hobbies ["movies" "music" "money"]})
输出:

"My name is John Doe. I live in Universal Studios. I am 50 yrs old. I like movies, music, money."
"My name is John Doe. I live in Universal Studios. I like movies, music, money"

自Clojure 1.5以来,有
cond->
/
cond->
->
/
->
一样工作,并带有确定是否执行单个步骤的条件:

(cond->
  (str "My name is " (:firstname p) " " (:lastname p) ".")
  (:showaddress p) (str "I live in " (:address p) ".")
  (:showage p)     (str "I am " (:age p) " yrs old.")
  ...)
这将是条件字符串构建的惯用解决方案。或者,您可以使用以下内容:

(clojure.string/join
  [(str "My name is " (:firstname p) " " (:lastname p) ".")
   (if (:showaddress p)
     (str "I live in " (:address p) "."))
   ...])

这使用了这样一个事实,即在连接字符串时,
nil
将被忽略。

为了避免重复任何无用的内容(例如,if条件或正在遍历所有内容的x),请定义要运行的测试列表,以及测试成功时要应用的函数。然后你就可以减少这个列表。在通过重复调用str构建字符串的简单情况下,您可以略去中间人,自己通过apply调用str:

(defn person-story [person]
  (let [tests [[:showaddress #(format " I live in %s." (:address %))]
               [:showage #(format " I am %s yrs old." (:age %))]
               [(comp seq :hobby) #(format " I like %s." (clojure.string/join ", " (:hobby %)))]]]
    (apply str (format "My name is %s %s." (:firstname person) (:lastname person))
           (for [[test f] tests
                 :when (test person)]
             (f person)))))