I quite like Python for teaching. And people praise it for the lambda
construct which is a bit like $\lambda$-abstraction in functional languages. However, it is broken!
To see how lambda
is broken, try generating a list of functions $[f_0, …, f_9]$ where $f_i(n) = i + n$. First attempt:
>>> fs = [(lambda n: i + n) for i in range(10)] >>> fs[3](4) 13
Wait a minute, fs[3](4)
ought to be 3 + 4 = 7
! It looks like all 10 functions share the same “last” value of i
, which is 9
. Indeed:
>>> [f(4) for f in fs] [13, 13, 13, 13, 13, 13, 13, 13, 13, 13]
This is certainly unexpected. Let us try to get around the problem by not using lambda
:
>>> fs = [] >>> for i in range(10): ... def f(n): return i+n ... fs.append(f) ... >>> [f(4) for f in fs] [13, 13, 13, 13, 13, 13, 13, 13, 13, 13]
Still not working, so the reason is deeper, probably in the way environments are handled. Maybe like this:
>>> fs = [] >>> for i in range(10): ... def f(n, i=i): return i+n ... fs.append(f) ... >>> [f(4) for f in fs] [4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
Victory! But try explaining to students what is going on.
Just to be sure, Haskell does the right thing, of course!
Prelude> let fs = [(\n -> i + n) | i <- [0..9]] Prelude> [f(4) | f <- fs] [4,5,6,7,8,9,10,11,12,13]
What were the implementors of Python thinking?!
@Aaron: yes, I think someone else pointed out a similar solution. But really, that doesn’t clarify anything. It’s a workaround.