it.", by Phillip Smith, in which the author wishes Perl

solutions were credited as much as solutions in other languages such as

Python and Ruby.

I agreed that Perl wasn't mentioned as much as it was, and a day or so

later I came across an example of why....

I monitor whats happening in Python, and came across a new recipe added

to Activestate code called: "Recipe 576961: Technique for cyclical

iteration", by Raymond Hettinger. On first, second, and third

readings, i just couldn't understand the need for the deferred_output

function; the whole recipe remained opaque:

Raymond's

code:

from itertools import tee, chain, islice

from heapq import mergedefhamming_numbers():

# Generate "5-smooth" numbers, also called "Hamming numbers"

# or "Regular numbers". See: http://en.wikipedia.org/wiki/Regular_number

# Finds solutions to 2**i * 3**j * 5**k for some integers i, j, and k.

defno_repeats(it):

last = None

foriinit:

ifiisnotlast:

yieldi

last = i

defdeferred_output():

foriinoutput:

yieldi

result, p2, p3, p5 = tee(deferred_output(), 4)

m2 = (2*xforxinp2) # multiples of 2

m3 = (3*xforxinp3) # multiples of 3

m5 = (5*xforxinp5) # multiples of 5

merged = merge(m2, m3, m5)

combined = chain([1], merged) # prepend a starting point

output = no_repeats(combined) # eliminate duplicates

returnresultif__name__ == '__main__':

I was hooked by the series however and so went looking for more

information.

### Perl

I came across a mention to the following page: "Infinite

lists in Perl" by Mark Dominus which is copyright 1997 by the

Perl Journal. Normally I wouldn't mention the article, as it spends

more time creating an implementation of generators in Perl as it does

on addressing the computation of Hamming numbers. It also uses the term

"stream" instead of generators. but maybe this is down to the age of

the article, i.e. 1997?

### Haskell

Looking a bit further, I found this Dr Dobbs Article, and this

commented Haskell

solution:

hamming = 1 : map (2*) hamming `merge` map (3*) hamming `merge` map (5*) hamming

where merge (x:xs) (y:ys)

| x < y = x : xs `merge` (y:ys)

| x > y = y : (x:xs) `merge` ys

| otherwise = x : xs `merge` ys

The Haskell solution lead me to think that maybe Python has an issue

with defining recursive generators, and some experimentation lead me to

believe that yep, maybe that was why Raymond has the deferred_output

function.

### My Python

Since I have trouble understanding Raymond s I went away and wrote my

own solution. It works. It can generate very large values of the

sequence quite quickly. But it does need memory to store

multiples:

from itertools import islice

from pprint import pprint as ppdefregularnumbergen(start = 1, multipliers=(2, 3, 5)):

'''\

Generates the Regular Number sequence defined here:

http://en.wikipedia.org/wiki/Regular_number

The sequence starts with 1 and consists of all multiples by 2, 3, or 5

of any number in the sequence in non-repeating, increasing order.

'''

multiples = [[]foriinmultipliers]

this = start

whileTrue:

yieldthis

# get multiples

formultiple, multiplierinzip(multiples, multipliers):

multiple.append(this * multiplier)

# get next

this = min(m[0]forminmultiples)

# remove this from multiples

formultipleinmultiples:

ifmultiple[0] == this:

delmultiple[0]if__name__ == '__main__':

Generating the following large values of the sequence took only seconds:

>>> print(list(islice(regularnumbergen(), 99999, 100001)))

[290142196707511001929482240000000000000, 290237644800000000000000000000000000000]

>>>

### Wrapup

Well, I've learnt a bit more about generators, the limitatins in their

Python implementation w.r.t. Haskel, and I've put more meat on why I

tend to not quote much Perl In this case, i couldn't see the wood for

the trees! (But I do quote Perl).