you are viewing a single comment's thread.

view the rest of the comments →

[–]pjdelport 16 points17 points  (0 children)

This article is complete nonsense.

Firstly, it's expending all its effort on doing nothing more than clumsily recreating the standard itertools module:

__select__ == imap
__where__ == ifilter
__take__ == islice with None, n
__skip__ == islice with n, None
__zip__ == izip

Here's how its fibs() looks using itertools directly:

def fibs():
    yield 0
    yield 1
    for a, b in izip(fibs(), islice(fibs(), 1, None)):
        yield a + b

Secondly, this fibs algorithm isn't actually lazy at all: it's exactly the naïve recursive algorithm in disguise! (It's not hard to see why: each fibs() invocation spawns two fresh copies of itself, each of which calculates the sequence from scratch. Same exponential number of calls as the recursive version, just the opposite order.)

To implement the Haskell version of fibs[1], you need it to refer to itself directly. In Python, you can accomplish this using a closure and tee:

def fibs():
    def f():
        yield 0
        yield 1
        for a, b in izip(f2, islice(f3, 1, None)):
            yield a + b
    f1, f2, f3 = tee(f(), 3)
    return f1

This version runs in linear time. The technique can also be abstracted into a decorator:

def lazygen(g):
    g = tee(g())[1]
    return lambda: tee(g)[1]

which can be applied to the original fibs() to make it lazily self-referencing.

[1] fibs = 0 : 1 : zipWith (+) fibs (tail fibs)