2016-03-29 1 views
0

Я хочу переписать (я не уверен, если оригинальная реализация ленивая из не) ленивой реализация Clojure перемежения с использованием lazy-seq, который работает следующим образом:ленивых повторного внедрение Clojure Interleaving

(take 4 (lazy-interleave ’(1 2 3) ’(a b c))) 
(1 a 2 b) 

I придумал что-то вроде этого, но я не знаю, почему он не работает:

(defn lazy-interleave [v1 v2] 
    (lazy-seq (concat (list (first v1) (first v2))) (lazy-interleave (next v1) (next v2))) 
    ) 

Edit:

Благодаря ответу Артура, вот модифицированный рабочий раствор:

(defn lazy-interleave [v1 v2] 
    (lazy-seq 
     (cons (first v1) (cons (first v2) (lazy-interleave (rest v1) (rest v2)))) 
    ) 
    ) 

ответ

3

Немного переформатирования раскрывает проблему:

(defn lazy-interleave [v1 v2] 
    (lazy-seq 
    (concat (list (first v1) (first v2))) 
    (lazy-interleave (next v1) (next v2)))) 

Другими словами, вы построения ленивую последовательность, которая, когда понял, , будет оценивать (concat (list (first v1) (first v2))), проигнорировать результат, а затем попытаться оценить и вернуть (lazy-interleave (next v1) (next v2)). Этот вызов lazy-interleave делает то же самое, снова отбрасывая первые элементы v1 и v2 и т. Д., До бесконечности.

Вы никогда не добираетесь до основания, потому что у вас нет пустой проверки, и так как (next nil) возвращает nil, он просто продолжает идти даже после того, как вы исчерпали обе последовательности. Вы не получаете StackOverflowError, потому что вместо рекурсии вы используете ленивые последовательности.

Правильная реализация будет выглядеть следующим образом:

(defn lazy-interleave [v1 v2] 
    (when (and (seq v1) (seq v2)) 
    (lazy-cat [(first v1) (first v2)] 
       (lazy-interleave (rest v1) (rest v2))))) 
+0

Спасибо, я не знал, что есть «ленивый кот». Только один вопрос: даже без «нуля» проверки с ленивой кошкой мы можем «взять» ограниченное количество элементов из «ленивого чередования», но почему мы не можем сделать это с ленивым секем? в вашем примере я получу '(1 ноль)' for '(возьмите 2 (lazy-interleave [1] [])), но даже используя' take' мой код не работает – Yar

+2

Как программист, который любит кошек , Я пытаюсь использовать эту функцию всякий раз, когда это можно сделать, чтобы соответствовать –

+0

@ArthurUlfeldt lol полностью ее получил. Еще раз спасибо. – Yar

1

interleave уже ленивый:

user> (interleave (take 5 (iterate #(do (println "sequence A:" %) (inc %)) 0)) 
        (take 5 (iterate #(do (println "sequence B:" %) (inc %)) 100))) 
sequence A: 0 
sequence B: 100 
sequence A: 1 
sequence B: 101 
sequence A: 2 
sequence B: 102 
sequence A: 3 
sequence B: 103 
(0 100 1 101 2 102 3 103 4 104) 


user> (take 4 (interleave (take 5 (iterate #(do (println "sequence A:" %) (inc %)) 0)) 
          (take 5 (iterate #(do (println "sequence B:" %) (inc %)) 100)))) 
sequence A: 0 
sequence B: 100 
(0 100 1 101) 

И ядро ​​это реализация выглядит так же, как ваш пример:

(lazy-seq 
     (let [s1 (seq c1) s2 (seq c2)] 
     (when (and s1 s2) 
      (cons (first s1) (cons (first s2) 
           (interleave (rest s1) (rest s2))))))) 

Кроме того, он также работает над более чем двумя последовательностями, поэтому у него есть другая реальность, что han в этом случае.