如何减少Clojure中的可读性?

Ken*_*Ken 4 readability clojure

一个reduce电话f首先有一个参数.从视觉上讲,这通常是表格中最重要的部分.例如

(reduce
 (fn [[longest current] x]
   (let [tail (last current)
         next-seq (if (or (not tail) (> x tail))
                    (conj current x)
                    [x])
         new-longest (if (> (count next-seq) (count longest))
                       next-seq
                       longest)]
     [new-longest next-seq]))
 [[][]]
 col))
Run Code Online (Sandbox Code Playgroud)

问题是,val论证(在这种情况下[[][]])和col论证在下面,下面,你的眼睛有很长的路要走,以匹配那些参数f.

如果它按此顺序,它看起来更具可读性:

(reduceb val col
  (fn [x y]
    ...))
Run Code Online (Sandbox Code Playgroud)

我应该实现这个宏,还是我首先接近这个完全错误?

ama*_*loy 5

你当然不应该写那个宏,因为它很容易写成函数.不过,我也不是非常热衷于把它写成一个函数; 如果你真的想将reduce与最后两个args配对,你可以写:

(-> (fn [x y]
      ...)
    (reduce init coll))
Run Code Online (Sandbox Code Playgroud)

就个人而言,当我需要像这样的大型函数时,我发现逗号实际上是一个很好的视觉锚点,并且更容易告诉最后一行有两个表单:

(reduce (fn [x y]
          ...)
        init, coll)
Run Code Online (Sandbox Code Playgroud)

更好的是通常不会首先写出如此大的减少量.在这里,您将至少两个步骤组合成一个相当大且困难的步骤,通过尝试立即找到最长的减少子序列.相反,尝试将集合拆分为递减的子序列,然后取最大的一个.

(defn decreasing-subsequences [xs]
  (lazy-seq
    (cond (empty? xs) []
          (not (next xs)) (list xs)
          :else (let [[x & [y :as more]] xs
                      remainder (decreasing-subsequences more)]
                  (if (> y x) 
                    (cons [x] remainder)
                    (cons (cons x (first remainder)) (rest remainder)))))))
Run Code Online (Sandbox Code Playgroud)

然后你可以替换你reduce:

(apply max-key count (decreasing-subsequences xs))
Run Code Online (Sandbox Code Playgroud)

现在,懒惰功能并不比你的减少特别短,但它只做一件事,这意味着它可以更容易理解; 此外,它有一个名称(给你一个关于它应该做什么的提示),它可以在你正在寻找基于减少子序列的其他属性的上下文中重用,而不仅仅是最长的.如果用函数参数替换>in ,则可以更频繁地重用它(> y x),允许您根据任何谓词拆分为子序列.另外,如上所述它是懒惰的,所以你可以在任何类型的减少都不可能的情况下使用它.

说到易于理解,你可以看到我误解了你的功能在阅读时应该做什么.我将把这个转换为严格增加的子序列的任务留给你,在那里我看起来像你在计算递减的子序列.