Clojure惰性序列问题
我正在处理4个法律问题,类似的问题不断出现。我将编写一个适用于除一个测试用例之外的所有测试用例的解决方案。它通常是检查延迟评估的一个。下面的解决方案适用于除最后一个测试用例之外的所有测试用例。我尝试过各种解决方案,似乎直到整数溢出时才停止计算。我在《Clojure的快乐》中读了关于懒惰序列的一章,但是我很难实现它们。有没有我忘记的经验法则,比如不要使用循环之类的Clojure惰性序列问题,clojure,Clojure,我正在处理4个法律问题,类似的问题不断出现。我将编写一个适用于除一个测试用例之外的所有测试用例的解决方案。它通常是检查延迟评估的一个。下面的解决方案适用于除最后一个测试用例之外的所有测试用例。我尝试过各种解决方案,似乎直到整数溢出时才停止计算。我在《Clojure的快乐》中读了关于懒惰序列的一章,但是我很难实现它们。有没有我忘记的经验法则,比如不要使用循环之类的 ; This version is non working at the moment, will try to edit a ver
; This version is non working at the moment, will try to edit a version that works
(defn i-between [p k coll]
(loop [v [] coll coll]
(let [i (first coll) coll (rest coll) n (first coll)]
(cond (and i n)
(let [ret (if (p i n) (cons k (cons i v)) (cons i v))]
(recur ret coll))
i
(cons i v )
:else v))))
好奇者的终极解决方案:
(fn i-between [p k coll]
(letfn [(looper [coll]
(if (empty? coll) coll
(let [[h s & xs] coll
c (cond (and h s (p h s))
(list h k )
(and h s)
(list h )
:else (list h))]
(lazy-cat c (looper (rest coll))))
))] (looper coll)))
当我想到惰性序列时,通常起作用的是增量
cons'ing
也就是说,每个递归步骤只向列表中添加一个元素,当然,您永远不会使用循环
所以你所拥有的是这样的:
(cons (generate first) (recur rest))
例如,在lazy seq
上包装时,仅实现序列中所需的元素
(take 5 (some-lazy-fn))
将只执行5
递归调用来实现所需的元素
对于4clojure
问题,这是一个试探性的、远不是完美的解决方案,它表明了以下观点:
(fn intercalate
[pred value col]
(letfn [(looper [s head]
(lazy-seq
(if-let [sec (first s)]
(if (pred head sec)
(cons head (cons value (looper (rest s) sec)))
(cons head (looper (rest s) sec)))
(if head [head] []))))]
(looper (rest col) (first col))))
在这里,局部递归函数是looper
,对于每个元素,测试谓词是否为true
,在这种情况下实现两个元素(添加交错元素),否则只实现一个
此外,还可以使用高阶函数避免递归
(fn [p v xs]
(mapcat
#(if (p %1 %2) [%1 v] [%1])
xs
(lazy-cat (rest xs) (take 1 xs))))
但是正如@noisesmith在评论中所说的,您只是调用一个调用
lazy seq
的函数,有两种方法可以生成一个lazy seq:调用lazy seq
函数,或者调用调用它的函数。如果我使用lazy cat并将其包装,它仍然不会计算lazy。你的第二个解决方案在末尾为(\uuuuu<:less[1 2 3 2 1 0])
添加了一个:less
。我知道,但它通过了测试,是一个没有递归的好例子。永远不要使用for
的建议是没有根据的:for
是懒惰的,并且通常是惰性seq生成函数的完美组件。例如,我不认为For
是这里最可读的选择,但这是我对这个4clojure问题的解决方案,稍微修改为For
而不是mapcat
。顺便说一句,(cons a(cons b xs))
最好写成(list*a b xs)
:list*
只是对cons
的一系列调用。