It is fallacious to suggest that in order to have generic iteration that supports non-list objects, we must abandon the classic list processing functions and give them alternative names and behaviors.
In the TXR Lisp dialect, classic functions like mapcar iterate over nonlists, without losing a shred of backward compatibility over lists.
For instance, we can iterate starting from an integer, in parallel with iterating over a list:
1> (mapcar 'cons '(a b c) 0)
((a . 0) (b . 1) (c . 2))
What we do is pattern the iteration abstraction after the car/cdr model, so that car/cdr iteration falls out as a straightforward special case.
To do this we define an iteration API with four operations:
iter-begin: construct the iterator from the sequence object
iter-more: test the iterator whether it has more elements
iter-item: if iter-more tested true, get the first item
iter-step: calculate iterator of rest of sequence
iter-step may be functional or destructive, so the caller must capture the new iterator returned as a value and must stop using the old one.
Integer:
1> (iter-begin 0) ;; identity
0
2> (iter-more 0) ;; true function: ignores argument, returns t.
t
3> (iter-item 0) ;; identity
0
4> (iter-step 0) ;; successor function
1
In the TXR Lisp dialect, classic functions like mapcar iterate over nonlists, without losing a shred of backward compatibility over lists.
For instance, we can iterate starting from an integer, in parallel with iterating over a list:
What we do is pattern the iteration abstraction after the car/cdr model, so that car/cdr iteration falls out as a straightforward special case.To do this we define an iteration API with four operations:
iter-step may be functional or destructive, so the caller must capture the new iterator returned as a value and must stop using the old one.Integer:
String: List: Without the check in (iter-step '(1 . 2)) we would get 2, and that would then iterate through 2, 3, 4, ...