我已将此代码(下面的代码段)从Python翻译为Clojure。我在这里用Clojure的while
替换了Python的loop-recur
构造。但这看起来并不惯用。
(loop [d 2 [n & more] (list 256)]
(if (> n 1)
(recur (inc d)
(loop [x n sublist more]
(if (= (rem x d) 0)
(recur (/ x d) (conj sublist d))
(conj sublist x))))
(sort more)))
这个例程给了我(3 3 31)
,这是279
的主要因素。对于256
,它提供(2 2 2 2 2 2 2 2)
,表示2^8
。
此外,对于较大的值,它会表现更差,例如987654123987546
而不是279
;而Python的对手就像魅力一样。
如何开始编写核心功能,而不是按原样翻译命令式代码?具体来说,如何改善这一点?
感谢。
[编辑]
这是我在上面提到的python代码,
def prime_factors(n):
factors = []
d = 2
while n > 1:
while n % d == 0:
factors.append(d)
n /= d
d = d + 1
return factors
答案 0 :(得分:2)
并非每个循环都能完全展开为优雅的“功能”分解。
@edbond建议的Rosetta Code解决方案非常简洁明了;我会说这是惯用的,因为没有明显的“功能”解决方案。我的机器上的解决方案运行速度明显快于987654123987546
的Python版本。
更一般地说,如果你想扩展对功能习语的理解,Bedra和Halloway的“Programming Clojure”(pp.90-95)使用{{1}对斐波那契序列的不同版本进行了极好的比较。 },lazy seqs和优雅的“功能”版本。 Chouser和Fogus的“Clojure的喜悦”(MEAP版本)也有很好的功能组合部分。
答案 1 :(得分:2)
Clojure中Python代码的直接翻译将是:
(defn prime-factors [n]
(let [n (atom n) ;; The Python code makes use of mutability which
factors (atom []) ;; isn't idiomatic in Clojure, but can be emulated
d (atom 2)] ;; using atoms
(loop []
(when (< 1 @n)
(loop []
(when (== (rem @n @d) 0)
(swap! factors conj @d)
(swap! n quot @d)
(recur)))
(swap! d inc)
(recur)))
@factors))
(prime-factors 279) ;; => [3 3 31]
(prime-factors 987654123987546) ;; => [2 3 41 14389 279022459]
(time (prime-factors 987654123987546)) ;; "Elapsed time: 13993.984 msecs"
;; same performance on my machine
;; as the Rosetta Code solution
您可以改进此代码,使其更具惯用性:
(loop []
(cond
(<= @n 1) @factors
(not= (rem @n @d) 0) (do (swap! d inc)
(recur))
:else (do (swap! factors conj @d)
(swap! n quot @d)
(recur))))))
(defn prime-factors [n]
(loop [n n
factors []
d 2]
(cond
(<= n 1) factors
(not= (rem n d) 0) (recur n factors (inc d))
:else (recur (quot n d) (conj factors d) d))))
== 0
替换为zero?
: (not (zero? (rem n d))) (recur n factors (inc d))
你也可以彻底检修它以制作它的懒惰版本:
(defn prime-factors [n]
((fn step [n d]
(lazy-seq
(when (< 1 n)
(cond
(zero? (rem n d)) (cons d (step (quot n d) d))
:else (recur n (inc d)))))
n 2))
我计划在这里有一个关于优化的部分,但我不是专家。我唯一可以说的是,当d
大于n
的平方根时,你可以通过中断循环来简化这段代码:
(defn prime-factors [n]
(if (< 1 n)
(loop [n n
factors []
d 2]
(let [q (quot n d)]
(cond
(< q d) (conj factors n)
(zero? (rem n d)) (recur q (conj factors d) d)
:else (recur n factors (inc d)))))
[]))
(time (prime-factors 987654123987546)) ;; "Elapsed time: 7.124 msecs"