[Tim on comparing fringes of two trees]:
In Icon you need to create co-expressions to solve this problem, because its generators aren't explicitly resumable, and Icon has no way to spell "kick a pair of generators in lockstep". But explicitly resumable generators are in fact "good enough" for this classic example, which is usually used to motivate coroutines.
Apparently they are good for lots of other things too. Tonight I implemented passing values using resume(). Next, I decided to see if I had enough magic juice to tackle the coroutine example from Gordon's stackless tutorial. Its turns out that I didn't need the extra functionality. Generators are enough. The code is not too long so I've attached it. I figure that some people might need a break from 2.1 release issues. I think the generator version is even simpler than the coroutine version. Neil # Generator example: # The program is a variation of a Simula 67 program due to Dahl & Hoare, # who in turn credit the original example to Conway. # # We have a number of input lines, terminated by a 0 byte. The problem # is to squash them together into output lines containing 72 characters # each. A semicolon must be added between input lines. Runs of blanks # and tabs in input lines must be squashed into single blanks. # Occurrences of "**" in input lines must be replaced by "^". # # Here's a test case: test = """\ d = sqrt(b**2 - 4*a*c) twoa = 2*a L = -b/twoa R = d/twoa A1 = L + R A2 = L - R\0 """ # The program should print: # d = sqrt(b^2 - 4*a*c);twoa = 2*a; L = -b/twoa; R = d/twoa; A1 = L + R; #A2 = L - R #done # getlines: delivers the input lines # disassemble: takes input line and delivers them one # character at a time, also inserting a semicolon into # the stream between lines # squasher: takes characters and passes them on, first replacing # "**" with "^" and squashing runs of whitespace # assembler: takes characters and packs them into lines with 72 # character each; when it sees a null byte, passes the last # line to putline and then kills all the coroutines from Generator import Generator def getlines(text): g = Generator() for line in text.split('\n'): g.suspend(line) g.end() def disassemble(cards): g = Generator() try: for card in cards: for i in range(len(card)): if card[i] == '\0': raise EOFError g.suspend(card[i]) g.suspend(';') except EOFError: pass while 1: g.suspend('') # infinite stream, handy for squash() def squash(chars): g = Generator() while 1: c = chars.next() if not c: break if c == '*': c2 = chars.next() if c2 == '*': c = '^' else: g.suspend(c) c = c2 if c in ' \t': while 1: c2 = chars.next() if c2 not in ' \t': break g.suspend(' ') c = c2 if c == '\0': g.end() g.suspend(c) g.end() def assemble(chars): g = Generator() line = '' for c in chars: if c == '\0': g.end() if len(line) == 72: g.suspend(line) line = '' line = line + c line = line + ' '*(72 - len(line)) g.suspend(line) g.end() if __name__ == '__main__': for line in assemble(squash(disassemble(getlines(test)))): print line print 'done'