(def inf-iter (f c)
" Creates a lazy-list-like scanner whose first element
is `c' and whose succeeding elements are the result of
`f' applied on the previous element. "
(let d nil
(make-scanner
'car (fn () c)
'cdr (fn () (or d (= d (inf-iter f (f c))))) )))
arc> (= p2 (inf-iter [* 2 _] 1))
#3(tagged scanner (#<procedure> . #<procedure>))
arc> (car p2)
1
arc> (repeat 10 (= p2 (cdr p2)) (prn (car p2)))
2
4
8
16
32
64
128
256
512
1024
nil
The more I think about these scanners, the cooler they seem. It's a very neat abstraction, and a great way to integrate laziness into Lisp in a very Lisp-y manner.
It would be neat too if function application would destructure using Arc-side 'car and 'cdr (Scheme side '_car '_cdr, or '__car '__cdr on Arc-wiki now that we have FFI). Basically the requirement for 'apply would be a scanner, not a 'cons; after all, 'apply does not mutate the applied list.
However as is it's possible to use p-m: or kennytilton's dsb (which should really be ds-b: and put on the arc-wiki.git) for destructuring scanners.
Also the syntax for creating scanners should really be neater. Possibly this might help:
(mac scanner args
(let (a d) nil
( (afn ((opt val . args))
(if
(iso opt ''car)
(= a val)
(iso opt ''cdr)
(= d val)
(err:tostring:pr "Unknown option - " opt))
(if args (self args)))
args)
(w/uniq (a-v d-v a-valid d-valid)
`(let (,a-v ,d-v ,a-valid ,d-valid) nil
(make-scanner
'car (fn ()
(if ,a-valid ,a-v
(= ,a-valid t
,a-v ,a)))
'cdr (fn ()
(if ,d-valid ,d-v
(= ,d-valid t
,d-v ,d))))))))
'inf-iter can then be defined somewhat more neatly as:
(def inf-iter (f c)
(scanner
'car c
'cdr (inf-iter f (f c))))
All the above untested of course, including the grandparent post ^^ I'm sitting bored in the office ^^
Yeah, agreed. In general, I'd like to see ac.scm calling out to Arc functions as much as possible, to maximize the power of in-Arc tinkering via redef/defm, like scanner.