在Clojure中重写一系列if语句

在Clojure中重写一系列if语句,clojure,Clojure,也许现在已经太晚了,但我似乎无法理解这一点。我正在创造一个像这样的东西 (defn new-psf [props] (let [psf (Psf.)] (if (contains? props :pageLn) (.setPageLn psf (props :pageLn))) (if (contains? props :pageNum) (.setPageNum psf (props :pageLn))) (if (contains? p

也许现在已经太晚了,但我似乎无法理解这一点。我正在创造一个像这样的东西

(defn new-psf
  [props]
  (let [psf (Psf.)]
    (if (contains? props :pageLn)
      (.setPageLn psf (props :pageLn)))
    (if (contains? props :pageNum)
      (.setPageNum psf (props :pageLn)))
    (if (contains? props :includedSources)
      (doseq [s (props :includedSources)]
        (.add (.getIncludedSources psf) s)))
    psf))
现在这看起来很难看,我不得不认为,有了重复的模式,Clojure有了更干净的方式。所有的cond*函数似乎都不合适。我自己对宏还不够好,无法创建新的东西

任何人对宏有什么想法可以让我做这样的事情:

(defn new-psf
  [props]
  (let [psf (Psf.)]
    (condd (partial contains? props)
      :pageLn (.setPageLn psf (props :pageLn))
      :pageNum (.setPageNum psf (props :pageNum))
      :includedSources (doseq [s (props :includedSources)]
                         (.add (.getIncludedSources psf) s)))
    psf))

似乎
condd
condp
几乎相同

(defn new-psf
  [props]
  (let [psf (Psf.)]
    (condp (contains? %2 %1) props
      :pageLn (.setPageLn psf (props :pageLn))
      :pageNum (.setPageNum psf (props :pageNum))
      :includedSources (doseq [s (props :includedSources)]
                         (.add (.getIncludedSources psf) s)))
    psf))
您甚至可以在condp中使用很少有用的:>>语法,只需做一些更改:

(defn new-psf
  [props]
  (let [psf (Psf.)]
    (condp (get %2 %1) props
      :pageLn :>> #(.setPageLn psf %)
      :pageNum :>> #(.setPageNum psf %)
      :includedSources #(doseq [s %]
                         (.add (.getIncludedSources psf) s)))
    psf))

如果我理解正确,那么无论第一个
If
测试是失败还是成功,以下条件仍然会被测试

听起来像是
cond->
的工作!与
condp
不同,它不会将评估短路到第一个匹配

(defn with-page-ln [psf v]
  (.setPageLn psf v)
  psf)

(defn with-page-num [psf v]
  (.setPageNum psf v)
  psf)

(defn with-included-sources [psf v]
  (doseq [s v]
    (.add (.getIncludedSources psf) s))
  psf)

(defn new-psf
  [props]
  (cond-> (Psf.)
          (contains? props :pageLn)          (with-page-ln (props :pageLn))
          (contains? props :pageNum)         (with-page-num (props :pageLn))
          (contains? props :includedSources) (with-included-sources (props :includedSources)))

我不确定你的Psf类是什么,所以让我们在一个熟悉的类上做这个

(def frame (doto (new javax.swing.JFrame) 
                 (.setContentPane (javax.swing.JPanel.))))
属性映射

(def props {:title "test" 
            :background java.awt.Color/blue 
            :buttons ["foo" "bar" "baz"]})
您可以使用地图,而不是一系列的
if
s

(def option-application 
       {:title (fn [x v] (.setTitle x v)) 
        :background (fn [x v] (.setBackground (.getContentPane x) v))
        :buttons (fn [x v] (doseq [btn v] (.add x (javax.swing.JButton. btn))))})
并根据
道具

(doseq [[k v] props] ((k option-application) frame v))
让我们看看我们美丽的相框

(doto frame (.pack) (.setVisible true))
若道具中缺少一个键,它在选项应用程序中的相应操作将永远不会被调用。如果顺序很重要,请使用数组映射


注意,仍然有很多重复,因为对于每个键,我都包装一个类似命名的setter。使用反射处理所有这些问题。请参见此处的
apply options
,它应该足够通用,可以在您的课堂上使用。跷跷板还有一个
cond doto
你可能想借。

谢谢,亚历克斯!我之前试图使
condp
工作,但是
contains?
的参数顺序错误,我认为它不会工作。如果其他人遇到此问题要执行
#(包含?%2%1)
#(获取%2%1)
,则只需执行一个小的修复程序,这样pred就是一个函数。这与列出的代码不同,因为它将在第一次匹配时停止,而不是执行所有匹配任务。你说得对。我可以发誓它昨晚起作用了。回到绘图板上。我想你的意思是“无论第一个
测试失败还是成功,以下条件仍然会被测试”,即与
condp
不同,它不会将评估短路到第一个匹配。是的,完全正确。非常感谢。如果你不介意,我会用你的话更新我的答案。