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)
我应该实现这个宏,还是我首先接近这个完全错误?
你当然不应该写那个宏,因为它很容易写成函数.不过,我也不是非常热衷于把它写成一个函数; 如果你真的想将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),允许您根据任何谓词拆分为子序列.另外,如上所述它是懒惰的,所以你可以在任何类型的减少都不可能的情况下使用它.
说到易于理解,你可以看到我误解了你的功能在阅读时应该做什么.我将把这个转换为严格增加的子序列的任务留给你,在那里我看起来像你在计算递减的子序列.