Как мне избежать клочковского поведения Clojure для ленивых последовательностей, которые я хотите короткое замыкание?

У меня есть длинная, ленивая последовательность, которую я хочу уменьшить и проверить лениво , Как только два последовательных элемента не = (или некоторый другой предикат) друг к другу, я хочу прекратить использовать список, который является дорогим для производства. Да, это звучит как take-while , но читайте дальше.

Я хотел написать что-то простое и элегантное, как это (притворяясь на минуту, что каждый? работает как ] уменьшить ):

(every? = (range 100000000))

Но это не работает лениво, и поэтому оно висит на бесконечных последовательностях. Я обнаружил, что это работает почти так, как я хотел:

(apply = (range 100000000))

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

;; Displays chunking behavior in groups of four on my system and prints 1 2 3 4
(apply = (map #(do (println %) %) (iterate inc 1)))

;; This prints 0 to 31
(apply = (map #(do (println %) %) (range)))

Я нашел обходной путь, используя take-while и count для проверки количества элементы взяты, но это довольно громоздко.

Должен ли я вежливо предложить Ричу Хикки, чтобы он сделал какую-то комбинацию , чтобы уменьшить и каждый? правильное короткое замыкание правильно, или я пропускаю некоторые очевидный путь, который уже существует?

РЕДАКТИРОВАТЬ: Два добрых человека опубликовали решения, позволяющие избежать разброса ленивых последовательностей, но как мне избежать чанкинга при применении , которое, по-видимому, потребляется в чанкованных группах по четыре?

РЕДАКТИРОВАТЬ # 2: Как отмечает Стюарт Сьерра, и я обнаружил, что это не так т на самом деле кусаться. Он просто действует как обычно, поэтому я назову это закрытым и дам ему ответ. Я включил небольшую функцию в отдельный ответ, чтобы выполнить уменьшающую часть проблемы для тех, кому это интересно.

14
задан ivar 5 August 2010 в 18:14
поделиться

2 ответа

ДВАЖДЫ ИСПРАВЛЕНО: Более простой способ разбить ленивую последовательность на части:

(defn unchunk [s]
  (when (seq s)
    (lazy-seq
      (cons (first s)
            (unchunk (next s))))))

Первая версия опущена (когда ... , поэтому она вернула бесконечную последовательность из нулей после завершения входной последовательности.

Вторая версия использовала сначала вместо seq ], поэтому он остановился на nil.

RE: ваш другой вопрос, «как мне избежать разбиения на фрагменты при применении, которое, кажется, потребляет фрагменты групп по четыре» :

Это связано с определением = , которое при заданной последовательности аргументов заставляет первые 4:

(defn =
  ;; ... other arities ...
  ([x y & more]
   (if (= x y)
     (if (next more)
       (recur y (first more) (next more))
       (= y (first more)))
     false)))
20
ответ дан 1 December 2019 в 12:12
поделиться

Если посмотреть в clojure.core на определение apply, становится очевидным, почему оно разбивается на группы по четыре, когда apply используется с бесконечной последовательностью. Reduce тоже не замыкается ... так что мне осталось написать собственное решение:

(defn reducep
  "Like reduce, but for use with a predicate. Short-circuits on first false."
  ([p coll]
     (if-let [s (seq coll)]
       (reducep p (first s) (next s))
       (p)))
  ([p val coll]
     (if-let [s (seq coll)]
       (if-let [v (p val (first s))]
         (recur p (first s) (next s))
         false)
       true)))

Затем, используя unchunk Стюарта (с дополнительными и )

(defn unchunk [s]
  (lazy-seq
   (cons (first s)
         (and (next s)
              (unchunk (next s))))))

I get:

(reducep = (map #(do (print %) %) (unchunk (range)))) ;; Prints 01, returns false
(reducep = (map #(do (print %) %) (repeat 20 1))) ;; returns true
(reducep = (map #(do (print %) %) (unchunk [0 0 2 4 5]))) ;; Returns false
(reducep = (map #(do (print %) %) (unchunk [2 2 2 2 2]))) ;; returns true

Если это работает и для вас, модифицируйте это.

РЕДАКТИРОВАТЬ : модифицированная версия unchunk Стюарта после его редактирования, вероятно, предпочтительнее той, что была в этом более раннем посте.

2
ответ дан 1 December 2019 в 12:12
поделиться
Другие вопросы по тегам:

Похожие вопросы: