Генераторы
Генератор — это функция, которая производит потенциально бесконечный поток значений. Каждый раз, когда функция производит значение, она приостанавливает себя и ожидает, пока вызывающая сторона запросит следующее значение.
- Макрос: iter-defun name args [doc] [declare] [interactive] body…
-
iter-defunопределяет функцию-генератор. Функция-генератор имеет такой же синтаксис, как и обычная функция, но работает по-другому. Вместо выполнения body при вызове, функция-генератор возвращает объект-итератор. Этот итератор выполняет body для генерации значений, излучая значение и приостанавливаясь, где появляетсяiter-yieldилиiter-yield-from. Когда body возвращается нормально,iter-nextсигнализируетiter-end-of-sequenceс результатом body в качестве данных условия.Любой вид кода Lisp допустим внутри body, но
iter-yieldиiter-yield-fromне могут появляться внутриunwind-protectформ.
- Макрос: iter-lambda args [doc] [interactive] body…
iter-lambdaпроизводит безымянную функцию-генератор, которая работает так же, как функция-генератор, созданная с помощьюiter-defun.
- Макрос: iter-yield value
Когда он появляется внутри функции-генератора,
iter-yieldуказывает, что текущий итератор должен приостановиться и вернуть value изiter-next.iter-yieldвычисляется как параметрvalueследующего вызоваiter-next.
- Макрос: iter-yield-from iterator
iter-yield-fromвозвращает все значения, которые производит iterator, и вычисляется как значение, которое функция-генератор iterator возвращает нормально. Пока он контролирует, iterator получает значения, отправленные в итератор с использованиемiter-next.
Для использования функции-генератора сначала вызовите её обычно, создавая объект итератор. Итератор — это конкретный экземпляр генератора. Затем используйте iter-next, чтобы извлечь значения из этого итератора. Когда больше нет значений для извлечения из итератора, iter-next поднимает условие iter-end-of-sequence с конечным значением итератора.
Важно отметить, что тела функций-генераторов выполняются только внутри вызовов iter-next. Вызов функции, определенной с помощью iter-defun, производит итератор; вы должны управлять этим итератором с помощью iter-next, чтобы что-то интересное произошло. Каждый вызов функции-генератора производит разный итератор, каждый со своим состоянием.
- Функция: iter-next iterator value
-
Извлечь следующее значение из iterator. Если больше нет значений для генерации (потому что функция-генератор iterator вернула значение),
iter-nextсигнализирует о состоянииiter-end-of-sequence; значение данных, связанное с этим состоянием, — это значение, с которым функция-генератор iterator вернула.value отправляется в итератор и становится значением, до которого вычисляется
iter-yield. value игнорируется для первогоiter-nextвызова данного итератора, так как в начале функции-генератора iterator функция-генератор не оценивает ни однуiter-yieldформу.
- Функция: iter-close iterator
Если iterator приостановлен внутри
unwind-protectвbodyformи становится недоступным, Emacs в конечном итоге выполнит обработчики разворачивания после прохода сборки мусора. (Обратите внимание, чтоiter-yieldнедопустимо внутриunwind-protectвunwindforms.) Чтобы убедиться, что эти обработчики будут выполнены до этого, используйтеiter-close.
Для упрощения работы с итераторами предоставляются некоторые вспомогательные функции:
- Макрос: iter-do (var iterator) body …
Выполнить body с var, связанным с каждым значением, которое производит iterator.
Утилита циклов Common Lisp также содержит функции для работы с итераторами. См. Утилиту циклов в Расширения Common Lisp.
Следующий фрагмент кода демонстрирует некоторые важные принципы работы с итераторами.
(require 'generator)
(iter-defun my-iter (x)
(iter-yield (1+ (iter-yield (1+ x))))
;; Return normally
-1)
(let* ((iter (my-iter 5))
(iter2 (my-iter 0)))
;; Prints 6
(print (iter-next iter))
;; Prints 9
(print (iter-next iter 8))
;; Prints 1; iter and iter2 have distinct states
(print (iter-next iter2 nil))
;; We expect the iter sequence to end now
(condition-case x
(iter-next iter)
(iter-end-of-sequence
;; Prints -1, which my-iter returned normally
(print (cdr x)))))
Copyright © 1990-1996, 1998-2022 Free Software Foundation, Inc.
Licensed under the GNU GPL license.
https://www.gnu.org/software/emacs/manual/html_node/elisp/Generators.html