473,830 Members | 1,883 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Whoa! Do Python and Lisp really have LAMBDA ?

Earlier Ed Schofield (thanks, man) warned us that

flist = []

for i in range(3)
f = lambda x: x + i
flist.append(f)

[f(1) for f in flist]

gives [3, 3, 3]. So much for the principle of minimum surprise!

Doing the same in Lisp (with lists instead of arrays),

(setf flist (loop for i from 0 to 2
collect (lambda (x) (+ x i))))

(loop for f in flist
collect (funcall f 1))

I got (4 4 4).

Lisp has many gotchas, I just wasn't ready for this one.
(Google for "lisp gotchas" - someone posted a comprehensive
list to c.l.l. in 1995. Every Lisper should read it)

I'm sure Haskell does this right. What about Scheme and ML?

Jul 18 '05 #1
10 2026
<mi*****@ziplip .com> wrote:
+---------------
| Doing the same in Lisp (with lists instead of arrays),
|
| (setf flist (loop for i from 0 to 2
| collect (lambda (x) (+ x i))))
|
| (loop for f in flist
| collect (funcall f 1))
|
| I got (4 4 4).
|
| Lisp has many gotchas, I just wasn't ready for this one.
+---------------

Why should this be considered a "gotcha"? It's doing exactly what
you asked it to: all three lambdas are closed over the *same* variable
binding, which was left holding "3" when the loop finished. Try it
this way instead and you might get what you wanted/expected:
(defparameter flist (loop for i from 0 to 2 collect (let ((u i))
(lambda (x) (+ x u)))))
FLIST (loop for f in flist collect (funcall f 1))
(1 2 3)


In this case the lambdas are closed over *distinct* bindings.
-Rob

-----
Rob Warnock <rp**@rpw3.or g>
627 26th Avenue <URL:http://rpw3.org/>
San Mateo, CA 94403 (650)572-2607

Jul 18 '05 #2
On Sun, 26 Oct 2003 02:53:58 -0600, rp**@rpw3.org (Rob Warnock) wrote:
<mi*****@ziplip .com> wrote:
+---------------
| Lisp has many gotchas, I just wasn't ready for this one.
+---------------

Why should this be considered a "gotcha"?


Because he's a troll.
Jul 18 '05 #3
> (setf flist (loop for i from 0 to 2
collect (lambda (x) (+ x i))))
(loop for f in flist
collect (funcall f 1))

I got (4 4 4).
Yes, that is suprising, although it makes more sense once you realize
that they all bind to the same i, which is mutated during the loop.
I'm sure Haskell does this right. What about Scheme and ML?


The equivalent in Scheme (named let) introduces a new binding with each
iteration, so it does what you expect.

(define flist
(let loop ((i 0) (r '()))
(cond ((> i 2) (reverse r))
(else (loop (+ 1 i)
(cons (lambda (x) (+ x i)) r))))))

(let loop ((l flist) (r '()))
(cond ((null? l) (reverse r))
(else (loop (cdr l)
(cons ((car l) 1) r)))))

Unlike the Lisp version of flist, the Scheme loop binds a new i for each
iteration. Therefore, each closure has its own i.

My Scheme version is much wordier than the Lisp version above. Perhaps
the more experienced schemers can show you a less verbose version that
still does what you want. I've always been fond of functional languages,
but I've only recently had the chance to work with them extensively, so
I'm still learning.
--
Bradd W. Szonye
http://www.szonye.com/bradd
My Usenet e-mail address is temporarily disabled.
Please visit my website to obtain an alternate address.
Jul 18 '05 #4
On Sun, 26 Oct 2003 00:11:05 -0700, mike420 wrote:

[...]
I'm sure Haskell does this right. What about Scheme and ML?


Indeed Haskell does this right.

OCaml does this right.

SML doesn't have a for loop. If you emulate it with recursion idiomatic
to SML (passing the incremented argument, not using a mutable reference)
then it will work.

Scheme doesn't have a for loop either, I think it's like in SML - or would
it be more idiomatic to use "set!"? in which case it would not work.

Ruby does this wrong if you use "for i in 0..2 do ... end" but right if
you use "(0..2).eac h do |i| ... end".

Smalltalk does this right, unless you use some ancient implementations
which make block parameters local to the method in which they are written.
I'm not sure how widespread are such implementations .

Perl does this right if you remember to use "foreach my $i (...)" instead
of "foreach $i (...)" or "foreach (...)". In the latter cases a global
variable is used which is obviously wrong. I think Perl courses should
emphasize "my" more.

In Java I think you can't reference a mutable variable from a local class
but you can reference a final variable, so it detects the problem and
requires manual creation of an immutable binding to work around it.

I suspect that the newer C# which will have anonymous functions does this
wrong.

What about Dylan? Erlang? Mercury?

Moral 1: first class functions are better used with functional style
(immutable data). It's because they make the time when something is
evaluated harder to see, which is fine as long as data is immutable.
In this example it's easy to see that the lambda is evaluated later
but it's not as easy to notice that it matters that the dereferencing of
the variable happens when the function is called, not when it's created.
By taking away the possibility of mutation you take away some surprises.

Moral 2: if you design a language with closures, it's better not to use
a shared mutable variable in a "for" loop.

--
__("< Marcin Kowalczyk
\__/ qr****@knm.org. pl
^^ http://qrnik.knm.org.pl/~qrczak/

Jul 18 '05 #5
Marcin 'Qrczak' Kowalczyk wrote:
Scheme doesn't have a for loop either, I think it's like in SML - or would
it be more idiomatic to use "set!"? in which case it would not work.


You forget do.
(And for-each and map)

--
Jens Axel S?gaard

Jul 18 '05 #6
On Sun, 26 Oct 2003 11:08:12 +0100, Marcin 'Qrczak' Kowalczyk <qr****@knm.org .pl> wrote:
On Sun, 26 Oct 2003 00:11:05 -0700, mike420 wrote:

[...]
I'm sure Haskell does this right. What about Scheme and ML?


Indeed Haskell does this right.

OCaml does this right.


Just for the record: Common Lisp also does it right. The fact that it
doesn't do what someone "expects" who hasn't read the spec doesn't
make its behaviour wrong.

As others have pointed out you can choose if you want all the closures
to capture the same binding or if you want each closure to capture a
new binding. This is a feature, not a bug.

Edi.
Jul 18 '05 #7


mi*****@ziplip. com wrote:
Earlier Ed Schofield (thanks, man) warned us that

flist = []

for i in range(3)
f = lambda x: x + i
flist.append(f)

[f(1) for f in flist]

gives [3, 3, 3]. So much for the principle of minimum surprise!

Doing the same in Lisp (with lists instead of arrays),

(setf flist (loop for i from 0 to 2
collect (lambda (x) (+ x i))))

(loop for f in flist
collect (funcall f 1))

I got (4 4 4).

Lisp has many gotchas, I just wasn't ready for this one.
(Google for "lisp gotchas" - someone posted a comprehensive
list to c.l.l. in 1995. Every Lisper should read it)

I'm sure Haskell does this right. What about Scheme and ML?


Common Lisp does it right.

(mapcar (lambda (f) (funcall f 1))
(mapcar (lambda (i)
(lambda (x) (+ x i)))
(list 1 2 3)))

.... This is what the Haskell code eventually boild down to.

It is Python that apparently cannot do this. But, in all fairness,
nowhere in Python there is a claim that lambda expressions are full fledged.

The LOOP based version of Common Lisp does not do what you think it does
because the LOOP semantics is not the one you think it is.

Of course, I can always come up with a nice set of macros that would
hide some of the syntactic messiness in CL (of course do not ask me to
change the evaluation rules for CL: CL is simply not lazy)

Cheers
--
Marco

Jul 18 '05 #8
In comp.lang.lisp Marco Antoniotti <ma*****@cs.nyu .edu> wrote:
Common Lisp does it right.

(mapcar (lambda (f) (funcall f 1))
(mapcar (lambda (i)
(lambda (x) (+ x i)))
(list 1 2 3)))

... This is what the Haskell code eventually boild down to.

It is Python that apparently cannot do this. But, in all fairness,
nowhere in Python there is a claim that lambda expressions are full fledged.


Python lambda isn't *that* limited. It's just that the equivalent is
rather ugly by Python standards:

[f(1) for f in
[(lambda i: lambda x: x + i)(y)
for y in [1, 2, 3]]]

This also works, but isn't any prettier:

map(lambda f: apply(f, (1,)),
map(lambda i:
lambda x: (x + i),
[1, 2, 3]))

(Bleah. All those colons and commas are giving me MPI flashbacks.)

--
Karl A. Krueger <kk******@examp le.edu>
Woods Hole Oceanographic Institution
Email address is spamtrapped. s/example/whoi/
"Outlook not so good." -- Magic 8-Ball Software Reviews
Jul 18 '05 #9
| (loop for f in flist
| collect (funcall f 1))
|
| I got (4 4 4).

RW> Why should this be considered a "gotcha"?

Because it is? The loop/collect idiom has a mostly functional feel to
it, while it is implemented imperatively.

It's an issue that becomes transparent once you become used to Common
Lisp, just like the semantic difference between DO in CL and in Scheme.
But it's still an issue.

Followups restricted.

Juliusz
Jul 18 '05 #10

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

14
2318
by: Quentin | last post by:
Dear Gurus, This is a fairly simple question, but I can't figure out what the answer is. I can easily change my code, but I want to know why I can't do this to further my knowledge of the C++ language (and OO): class a { public: a(){ vm(); }
0
9752
by: Kirt Loki Dankmyer | last post by:
So, I download the latest "stable" tar for perl (5.8.7) and try to compile it on the Solaris 8 (SPARC) box that I administrate. I try all sorts of different switches, but I can't get it to compile. I need it to be compiled with threads. Anyone have any wisdom on how best to do this? Here's a transcript of my latest attempt. It's long; you might want to skip to the bottom, where I try "make" and the fatal errors start happening.
5
1744
by: sparks | last post by:
I am about to pull my hair out on this one. its a class stack with push and pop but one time its trying to find a } at the end of the code the next it says that I need a } after private man I know I am kinda new but this is driving me up the wall .... Should I start over or what. I keep adding things trying to get it to work but no success.
37
3878
by: Ian Rastall | last post by:
I've been working on an online books site for almost four years now, and have been putting smart quotes in each book. This is a major hassle, and I'm beginning to think it's not worth it. Is there a good reason not to use them in the first place? It would certainly be simple to convert back to straight quotes. Ian -- http://sundry.ws/
67
9938
by: lcw1964 | last post by:
This may be in the category of bush-league rudimentary, but I am quite perplexed on this and diligent Googling has not provided me with a clear straight answer--perhaps I don't know how to ask the quesion. I have begun to familiarize myself here with the gcc compiler in a win32 environment, in the form of MinGW using both Dev C++ and MSYS as interfaces. I have recompiled some old math code that uses long double types throughout and...
12
1637
by: Chief | last post by:
Hey I have a CODE that some 1 wrote however he use this line x= (y=4,z=6); ( by the way the output of this line is x=6 , y=4 , z=6 ) i was wondring in what situation i will have to use it? and does it good for? Second thing Can some 1 explain me the way to use the MAX_RAND while
14
2084
by: seralasu | last post by:
Hi, I have refresh problem.When user does refresh or clicks F5 then form variables again posting. It crates same a lot of inserts. I don't know How to solve it.
158
7927
by: pushpakulkar | last post by:
Hi all, Is garbage collection possible in C++. It doesn't come as part of language support. Is there any specific reason for the same due to the way the language is designed. Or it is discouraged due to some specific reason. If someone can give inputs on the same, it will be of great help. Regards, Pushpa
0
9777
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
0
9635
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
0
10473
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth. The Art of Business Website Design Your website is...
1
10518
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
0
9307
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own.... Now, this would greatly impact the work of software developers. The idea...
0
5614
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
0
5772
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
1
4407
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
3
3070
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.