2010-08-16 3 views
10

Я слышал, что называют stream, как infinite list,, а иногда даже в качестве lazy sequence.Каков правильный термин для следующего шаблона функционального программирования?

Каков правильный термин для следующего шаблона? (Clojure код показан)

(def first$ first) 

(defn second$ [str] 
    (cond 
    (empty? str)() 
    true ((first (rest str))))) 

(defn stream-builder [next_ n] 
    (cons n (cons (fn [] (stream-builder next_ (next_ n)))()))) 

(defn stream [str n] 
    (cond 
    (= 0 n)() 
    true (cons (first$ str) (stream (second$ str) (- n 1))))) 

(def odd 
    (stream-builder (fn [n] 
     (+ 2 n))1)) 

(println (stream odd 23)) 

> (1 3 5 7 9 11 13 15 17 19 21 23 25 27 29 31 33 35 37 39 41 43 45) 
+1

Я не уверен, что вы просите. Похоже, вы уже нашли для него 3 имени. Что, по вашему мнению, сделает любой ответ более «правильным», чем любой другой из этих синонимов? – Ken

ответ

14

Короткий ответ: stream-builder возвращает функцию, которая возвращает бесконечную последовательность/список, который должен быть оценен «лениво» (так как вы не можете оценить что-то бесконечно долго в конечное время). В мире Clojure вы, вероятно, не должны называть ничто из вашего примера «потоками», чтобы избежать путаницы с другой концепцией.

Более длинный ответ:

Побочным эффектом разнообразия мысли в языках программирования является то, что мы часто используем одни и те же слова для разных значений. Все три слова, которые вы упомянули («Поток», бесконечный список »,« ленивая последовательность »), относятся к обрабатывающим элементам серийным образом, а в Clojure мы называем эти« последовательности ». Тем не менее, нюансы, подразумеваемые каждым, немного отличаются.

а «поток» в целом относится к некоторой последовательности элементов, и в настоящее время часто используется в контексте конечных последовательностей символов. часто эти последовательности символов приходят из файла, сетевой источника, или Unix трубы.

Если последовательность определяется таким образом, что она имеет бесконечное количество элементов, мы можем назвать ее бесконечной последовательностью. Обычно бесконечные последовательности представлены внутри как linked list, поэтому мы можем назвать эти «бесконечные списки». Хотя, честно говоря, я бы предпочитают слышать термин «бесконечная последовательность» в сообщество Clojure, поэтому мы не привязаны к конкретной реализации.

И, наконец, нюанс «ленивой последовательности» в Clojure относится к шаблону последовательной оценки структуры данных, которая встречается «по требованию». Другими словами, акцент здесь делается на ленивый характер оценки; значение определенного элемента в последовательности фактически не вычисляется до тех пор, пока вы его не попросите.

В целом, в Clojure вы должны использовать слово:

  • «список», чтобы сослаться на что-то с реализацией связанного списка
  • «ленивый», чтобы обратиться к вещам, которые оценивают по требованию
  • «бесконечной» для обозначения последовательностей, которые не имеют конечного размера (и, следовательно, должны быть ленивым)
  • «поток» для обозначения трубы типа (символов) последовательности из внешнего источника
+0

Основываясь на вопросе, я ожидаю, что короткий ответ будет 1-2 слова ... – Qwertie

10

Это не ответ на ваш вопрос, но в интересах написания «хорошего» кода clojure, я хотел бы указать на некоторые вещи с вашим примером.

Одним из преимуществ функционального стиля является способность создавать функции вместе. Но если вы посмотрите на функции, которые вы написали, они индивидуально не делают многого, не в зависимости от функциональности, предоставляемой в другом месте.

Например, stream-builder просто возвращает список из двух элементов: n и анонимную функцию для обработки псевдорекурсии.

Я предполагаю, что вы пытались идти на ленивую последовательность, но для этого требуются вспомогательные функции, которые знают о деталях реализации, чтобы реализовать следующий элемент, а именно: stream и second$. К счастью, вы можете вместо этого выполнить его следующим образом:

 
(defn stream-builder [f x] ; f is idiomatic for a function arg 
    (lazy-seq    ; n is idiomatic for a count, so use x instead 
    (cons x 
     (stream-builder f (f x))))) 

выше будет на самом деле возвращает бесконечную последовательность значений, так что мы должны вытащить предельное поведение, которая в комплекте внутри stream:

 
(defn limit [n coll] ; coll is idiomatic for a collection arg 
    (lazy-seq   ; flipped order, fns that work on seqs usually take the seq last 
    (when (pos? n) 
     (when-let [s (seq coll)] 
     (cons (first s) 
      (limit (dec n) (next s))))))) 

выше будет лениво вернуться к n элементов coll:

 
user=> (limit 5 (stream-builder inc 1)) 
(1 2 3 4 5) 

В конце каждая функция хорошо справляется и может быть скомбинирована с другими функциями:

Наконец, вы определили odd как ленивую последовательность нечетных целых чисел. Опасность состоит в том, что последовательность будет придерживаться, когда она будет реализована (это называется «удерживание головы» последовательности). Это может излишне занять избыточную память, чтобы удерживать каждый элемент, когда-либо реализованный, и предотвращает сбор мусора.

Чтобы решить эту проблему, либо не DEF ленивой последовательности, или DEF его с пределом, например:

 
(def odds (limit 23 (stream-builder #(+ 2 %) 1))) 

Для дальнейшего использования, что мы только что написали доступно в базовой Lib, как iterate и take, соответственно:

 
user=> (take 5 (iterate inc 1)) 
(1 2 3 4 5) 
+0

+1 для приятного разбиения того, как писать идиоматический Clojure! –

 Смежные вопросы

  • Нет связанных вопросов^_^