Вот примерно эквивалентна функции генерации разделов в виде последовательности последовательностей:
(defn bar
([n] (bar n n))
([n k]
(if (zero? n)
[[]]
(for [i (range 1 (inc (min n k))), tail (bar (- n i) i)]
(cons i tail)))))
Например,
(bar 5)
; ((1 1 1 1 1) (2 1 1 1) (2 2 1) (3 1 1) (3 2) (4 1) (5))
Как ленивый bar
?
for
ленив.
- , чтобы сделать его более ленивым, оберните тело в
lazy-seq
.
У меня есть сомнения по поводу выше.
- Функция пересчитывается на глубину
n
.
- Обертывание тела в
lazy-seq
Я подозреваю, что просто кладет вверх по ленивым последовательностям, создавая так же глубокий рекурсивный стек вызовов при доступе к первому элементу .
Кроме того, повторно используются те же самые tail
s; тем более, что (bar n k)
одинаково для всех k >= n
.
Если производительность этой функции является особой проблемой, существуют итеративные алгоритмы с постоянным временем на шаг. Как следует из комментария @ CharlesDuffy, они могут быть повторно отстроены, чтобы создать ленивые последовательности.
Зачем смотреть в хрустальный шар, когда вы можете прочитать книгу?
Стандартное пространство имен clojure.math.combinatorics
, размещено here, содержит функцию partition
, которая создает ленивую последовательность разделов любой последовательности объектов - быстро. Целочисленный раздел - это где мы подсчитываем элементы каждого раздела одинаковых объектов. Они выходят в обратном лексикографическом порядке.
Например
(map #(map count %) (combo/partitions (repeat 5 :whatever)))
;((5) (4 1) (3 2) (3 1 1) (2 2 1) (2 1 1 1) (1 1 1 1 1))
Без сомнения, код может быть урезанным иметь дело только с этим случаем.
Действительно, если вы думаете, на минуту о том, как ленивые последовательности работы, вы поймете, что, будучи в состоянии иметь все свое состояние инкапсулированный для 'recur' вызова в значительной степени точно то же самое, имея свое состояние инкапсулированный для отложенного (ленивого) исполнения! –
@CharlesDuffy Я был бы признателен, если вы покажете мне пример для этого вопроса. – SaltyEgg