【问题标题】:Rewrite a series of if statements in Clojure在 Clojure 中重写一系列 if 语句
【发布时间】:2014-02-12 05:15:46
【问题描述】:

也许只是太晚了,但我似乎无法弄清楚这一点。我正在创建看起来像这样的东西

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

【问题讨论】:

    标签: clojure


    【解决方案1】:

    好像conddcondp差不多?

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

    【讨论】:

    • 谢谢,亚历克斯!我试图让condp 更早地工作,但是contains? 的参数顺序错误,我认为它不会起作用。如果其他人遇到此问题以执行 #(contains? %2 %1)#(get %2 %1) 以使 pred 成为一个函数,则只需一个小修复。
    • 这与列出的代码不同,因为它会在第一次匹配时停止,而不是执行所有匹配
    • 当。你是对的。我可以发誓昨晚它还在工作。回到绘图板。
    【解决方案2】:

    如果我没看错,第一个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)))
    

    【讨论】:

    • 我认为您的意思是“无论第一个 if 测试是否失败或成功,以下条件仍在测试中”,即与 condp 不同,它不会短路对第一场比赛的评估。
    • 是的,完全正确。谢谢 !如果你不介意,我会用你的话更新我的答案。
    【解决方案3】:

    我不确定你的 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"]})
    

    您可以使用地图而不是一系列ifs

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

    并根据props申请

    (doseq [[k v] props] ((k option-application) frame v))
    

    让我们看看我们漂亮的框架

    (doto frame (.pack) (.setVisible true))
    

    如果 props 中缺少某个键,则永远不会调用 option-application 中的相应操作。如果顺序很重要,请使用数组映射。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-01-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-05-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多