2013-03-09 83 views
1

我想在Clojure中编写一个简洁,懒惰的Pascal's Triangle,旋转使得行/列遵循三角形的对角线。也就是说,我要产生懒惰seqs以下懒惰序列:Clojure中的懒惰帕斯卡三角形

((1 1 1 1 ...) 
(1 2 3 4 ...) 
(1 3 6 10 ...) 
... 
) 

我写的代码是:

(def pascal 
    (cons (repeat 1) 
     (lazy-seq 
      (map #(map + %1 %2) 
       (map #(cons 0 %) (rest pascal))) 
       pascal 
     ))) 

使每一行是通过将形成右移它自己的版本到前一行。问题是,它永远不会超过第一行,因为那时(map #(cons 0 %) (rest pascal)))是空的。

=> (take 5 (map #(take 5 %) pascal)) 
((1 1 1 1 1)) 

什么是明智的解决方法?我在Clojure编程方面相当陌生,并且思考它涉及的问题的方式非常不同,所以我非常感谢任何有经验的人提出的建议。

回答

5

简洁慵懒

(def pascal (iterate (partial reductions +') (repeat 1))) 

(map (partial take 5) (take 5 pascal)) 
;=> ((1 1 1 1 1) 
; (1 2 3 4 5) 
; (1 3 6 10 15) 
; (1 4 10 20 35) 
; (1 5 15 35 70)) 

但是太懒?

(take 5 (nth pascal 10000)) 
;=> StackOverflowError 

再次尝试

(take 5 (nth pascal 10000)) 
;=> (0) 

嗯,哦,重新开始,并尝试,再尝试

(def pascal (iterate (partial reductions +') (repeat 1))) 
(count (flatten (map (partial take 5) (take 100000 pascal)))) 
;=> 500000 

现在这些都在你的堆

(take 5 (nth pascal 100000)) 
;=> (1 100001 5000150001 166676666850001 4167083347916875001) 
+0

+1。你知道为什么第二次调用'(拿5(第n次pascal 10000))'给第一个结果以不同的结果吗? StackOverFlowError以某种方式破坏序列?另外,在'+'之后有一个'''符号,我不认为你需要它。 – OpenSauce 2013-03-12 10:51:32

+1

@OpenSauce准确地说,这表明只调用lazy-seq的第一次和缓存结果行为。那个产生这个异常的地方不会被再次调用,并且由REPL处理的异常缓存了伪造结果。 +'会在需要时自动升级到'BigInt'。如果我采用了6而不是5,那么就会显示出来。 – 2013-03-12 12:02:27

2

帕斯卡不应该是一个var,而应该是一个产生的函数无限的seqs。

Check out this question for usage on lazy-seq

BTW,试试这个:

(defn gennext [s sum] 
    (let [newsum (+ (first s) sum)] 
    (cons newsum 
      (lazy-seq (gennext (rest s) newsum))))) 

(defn pascal [s] 
    (cons s 
     (lazy-seq (pascal (gennext s 0))))) 

enter image description here

(帕斯卡(重复1))为您提供整数溢出异常但这意味着它产生了无限seqs。您可以使用+'来使用大整数。

+0

@A。韦伯的代码更好,他使用我不知道的减少。 – yehe 2013-03-09 16:01:07

+0

你的解释可能对于OP来说更有帮助:)。但是我会避免使用'seq'作为绑定符号,因为它已经是一个常用的函数。 – 2013-03-09 16:04:22