用Clojure编写Pascal三角形的更为惯用和简洁的方法是什么?

max*_*man 3 idiomatic clojure pascals-triangle

我实施了一个天真的解决方案来打印Pascal的N深度三角形,我将在下面包含它.我的问题是,在哪些方面可以改进,使其更加惯用?我觉得有很多东西看起来过于冗长或尴尬,例如,这块if感觉不自然:(if (zero? (+ a b)) 1 (+ a b)).感谢您的任何反馈,谢谢!

(defn add-row [cnt acc]
  (let [prev (last acc)]
    (loop [n 0 row []]
      (if (= n cnt)
        row
        (let [a (nth prev (- n 1) 0)
              b (nth prev n 0)]
          (recur (inc n) (conj row (if (zero? (+ a b)) 1 (+ a b)))))))))


(defn pascals-triangle [n]
  (loop [cnt 1 acc []]
    (if (> cnt n)
      acc
      (recur (inc cnt) (conj acc (add-row cnt acc))))))
Run Code Online (Sandbox Code Playgroud)

ama*_*loy 8

(defn pascal []
  (iterate (fn [row]
             (map +' `(0 ~@row) `(~@row 0)))
           [1]))
Run Code Online (Sandbox Code Playgroud)

或者,如果你想要最大限度的简洁:

(defn pascal []
  (->> [1] (iterate #(map +' `(0 ~@%) `(~@% 0)))))
Run Code Online (Sandbox Code Playgroud)

为了扩展这个:高阶函数透视图是查看原始定义并实现类似:"我实际上只是f在初始值上计算函数f,然后f再次调用,然后再次......" .这是一个常见的模式,所以有一个函数被定义为覆盖你的无聊细节,让你只需指定f和初始值.并且因为它返回一个惰性序列,所以您不必立即指定n:您可以推迟,并使用完整的无限序列,以及您想要的任何终止条件.

例如,也许我不想要第一n行,我只想找到第一行,其总和是一个完美的正方形.然后我可以(first (filter (comp perfect-square? sum) (pascal))),而不必担心n我需要预先选择多大(假设明显的定义perfect-square?sum).

感谢fogus的改进:我需要使用+'而不仅仅是+这样,当它过去时它不会溢出Long/MAX_VALUE.

  • 这将很快溢出int.您可以将"1N"添加到种子向量中以避免它,但它看起来并不漂亮.虽然运行`(取500(pascal))`在滚动时在输出中显示一些有趣的正弦模式. (2认同)

Ank*_*kur 5

(defn next-row [row]
  (concat [1] (map +' row (drop 1 row)) [1]))

(defn pascals-triangle [n]
  (take n  (iterate next-row '(1))))
Run Code Online (Sandbox Code Playgroud)