Spec-Zone.ru › Elisp

Генераторы

Генератор — это функция, которая производит потенциально бесконечный поток значений. Каждый раз, когда функция производит значение, она приостанавливает себя и ожидает, пока вызывающая сторона запросит следующее значение.

Макрос: 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

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API