Python
Firstly, halfway across the planet, Sid created what could be for most part Yield the Magnificent for Python. (I am not fully convinced that he hasn’t lost property 6, but he has fixed 3 and 5.) But that should not come as much of a surprise to me because I have met few Py programmers like Sid :) Here is Sid’s Iterators that Listen
Scheme
Here is something that I have for scheme. It needs to have details ironed out. But effectively this does a coroutining “transform” of the caller. This puts it in the same category of ‘solution’ as ruby’s ‘generator’ class. This is also the operational equivalent of what py and c# have done. In the scheme world resume state is maintained by a continuation. In the Py or C# world, state is maintained by creating an object. For the scheme solution below, the basic ideas came from the brain storming session with William Byrd and Matt Ellis on this Friday.
Here is the scheme code:
(define coroutine
(lambda (prod)
(list (lambda (ret)
(let ((esc (car ret)))
(list (lambda (x) x)
(prod (lambda (it)
(let ((res (call-with-current-continuation
(lambda (k)
(esc (list k it #t))))))
(set! esc (car res)) ;Evil!
(cadr res))))
#f)))
#t #t)))
(define move-next
(lambda (co)
(call-with-current-continuation
(lambda (esc)
((car co) (list esc (cadr co) (caddr co)))))))
(define valueof?
(lambda (co) (cadr co)))
(define finished?
(lambda (co) (caddr co)))
(define set-return
(lambda (co val) (list (car co) val (caddr co))))
Writing a Producer / Generator / Iterator
One this is in place one can write an iterator that looks like so –
(define even
(lambda ()
(lambda (yield)
(let loop ((i 0))
(display (yield i))(newline)
(loop (+ i 2))))))
It is conceivable that we can have a macro to hide the currying of the inner lambda (yield). However it is easy to see that One can write producers that assume that they have a yield keyword handy.
Writing the consumer
To use the use the iterator as a first class object, you simply do –
(let loop ((co (coroutine (even))))
(let ((co (move-next co)))
(display "Yielded ")(display (valueof? co))(newline)
(loop co)))
Consumer code like the above is free from any forced invocation by the producer and hence does not need a ‘break’.
Functional programming
The co objects are first class and can be passed around – they are not bound to any syntactic structure. Hence having a yield facility is now meaningful in a functional context (which was one of Will Byrd’s concerns). The implementation of the coroutine is itself is not functional.
Lockstep iteration / apply-iterator / Iterator composition
It is conceivable that when you have a one one producer you might want a syntactic structure that also gives you a break.
However I don’t think its meaningful to create a general purpose apply-iterator. The reason is simple: Iterators are blocks of code that can yield a arbitrary number of values. If you decide to lockstep with each iterator producing a different number of yields, when should the composition of these iterators stop? There would be problems that need all of them can halt when the first one halts. There would be others where you might want the last iterator to stop before the the whole structure stops. So at the least you need at least ‘and’ and ‘or’ semantics between the finished cases. There might be algorithms where you need other behaviors.
Instead of defining these syntactic structures and defining rules for composition it is sufficient to convert individual iterators into coroutines. You can see that it would be very handy to have some nice list comprehensions to make it easy to use several coroutines in combination. As a matter of fact, all sorts of useful macros could be devised. However, there maybe no useful apply-iterator operator.
Now who can fix my imperative favorites, C# and Ruby?
Remember Me
a@href@title, strike
Powered by: newtelligence dasBlog 2.0.7226.0
Disclaimer The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.
© Copyright 2008, Roshan James
E-mail