Skip to content

Instantly share code, notes, and snippets.

@thierryvolpiatto
Created May 28, 2025 14:26
Show Gist options
  • Save thierryvolpiatto/fc95d8e4d079376a0abf2bae381242e6 to your computer and use it in GitHub Desktop.
Save thierryvolpiatto/fc95d8e4d079376a0abf2bae381242e6 to your computer and use it in GitHub Desktop.
Iterator with oclosure
;;; ocl-iterator.el --- define iterator with oclosure -*- lexical-binding: t -*-
;;; Code:
(oclosure-define ocl-iterator
"Return an iterator from SEQ."
(seq :type 'list :mutable t)
(cycle :type 'boolean)
(changing-direction :type 'boolean :mutable t)
(element :mutable t)
(direction :type 'symbol :mutable t))
(defun ocl-iterator (seq &optional cycle)
"Return an iterator from SEQ.
When CYCLE is non nil make the iterator infinite.
The iterator is mutable, its direction can be changed at anytime with
the function `ocl-iterator-reverse', when doing so the sequence
handled by the iterator is reversed from the last element yielded.
Elements of the iterator can be accessed via the ocl-iterator--* fns.
All the oclosure slots are mutable but the only one that can be
changed safely is \\='changing-direction', expect weird behavior if
you try to modify other elements externally."
(oclosure-lambda (ocl-iterator (seq seq)
(cycle cycle)
(tmp-seq seq)
(element (car seq))
(direction 'right)
(changing-direction nil))
()
(let ((elm (car tmp-seq))
revlist queue index)
(if changing-direction
(setq revlist (reverse seq)
queue (memql element revlist)
direction (pcase direction
('left 'right)
('right 'left))
index (- (length seq) (length queue))
seq (append queue (take index revlist))
tmp-seq (cddr seq)
elm (cadr seq)
changing-direction nil)
(setq tmp-seq (if cycle
(or (cdr tmp-seq) seq)
(cdr tmp-seq))))
(setq element elm))))
(defun ocl-iterator-reverse (iterator)
(setf (ocl-iterator--changing-direction iterator) t))
(defun ocl-iterator-next (iterator)
(and iterator (funcall iterator)))
;; (setq A (ocl-iterator '(a b c d e f g) 'cycle))
;; (ocl-iterator-next A)
;; (ocl-iterator-reverse A)
;; (ocl-iterator-next A)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment