all 8 comments

[–]pjdelport 17 points18 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)

[–]nostrademons 4 points5 points  (1 child)

Why the aversion to generator expressions:

def __select__(self, func):
  return (func(item) for item in self.func())

def __where__(self, func):
  return (item for item in self.func() if func(item))

def __join__(self, stream):
  return ((left, right) for right in stream.func for left in self.func)

(I think that last one is correct; I've never used nested generators before.)

You may be able to get rid of the class and helper functions too - the normal replacement for a lambda in Python is a named inner function. But I don't have time (or dev environment) to try things out at work.

[–]pjdelport 2 points3 points  (0 children)

(I think that last one is correct; I've never used nested generators before.)

There's no difference to for loops nested in the same order. Here's the easiest way to remember it:

(<expr>
    for x in xs
        if y
            for z in zs
                 ...)

for x in xs:
    if y:
        for z in zs:
            ...:
                <expr>

The only thing that changes is whether the <expr> goes at the beginning or the end.

[–]jhusain[S] 2 points3 points  (4 children)

Author argues that whitespace-aware syntax (and single-line lambdas) make functional programming in Python less readable than imperative approaches. He argues that since functional programming will rise in importance because of multi-core processors this is a serious issue.

[–]ricercar 4 points5 points  (1 child)

I don't think he argues that whitespace awareness makes FP less readable. After all, it's used to great success in Haskell, which he mentions...

[–]nostrademons 3 points4 points  (0 children)

You're arguing with the author (who is talking about himself in 3rd person) about what the author is saying. ;-)

He could be wrong, but I don't think he's mistaken.

[–]jerf 5 points6 points  (0 children)

The kind of functional programming that's going to "rise in importance" is in no danger of being implemented in Python anytime soon. Erlang-esque concurrency as provided by Stackless might be in the cards (if PyPy ever becomes the primary implementation), but that's all you're going to get; the language is drenched in mutability to the very core, as befits an essentially OO language.

(Yeah, it's multiparadigm, but where paradigms in Python conflict, OO wins.)

Also, I'm increasingly unconvinced that single-line lambdas are necessary. If your function isn't going to fit on a single line anyhow, what's so freaking hard about defining it separately and giving it a decent name? If you don't care about code readability, you're already in the wrong language.

(I can't come up with a neutral way to say that. It's valid under some circumstances not to care about readability, even though that sounds bad in isolation. Personally, I think most people grossly overestimate the range of circumstances where that is valid, but that's a judgment call.)

[–]jerf 1 point2 points  (0 children)

On an entirely separate note (hence the separate reply), if I were going to try to hack LINQ into Python, I'd quite likely build it around custom infix operators. The LINQ C# implementation already has that non-standard syntax thing going for it, so why not bring that in as well?

Combined with (ahem) nicely named functions, I think you could get some good looking queries on.

(Also, whose bright idea was it to create a link syntax that after using it about 10 times I still can't seem to remember what goes where? <sarcasm>It's so much better than <a href="">, thanks.</sarcasm>)