Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #6711 > unrolled thread

Something is rotten in Denmark...

Started byharrismh777 <harrismh777@charter.net>
First post2011-05-31 01:48 -0500
Last post2011-06-01 08:40 +1000
Articles 20 on this page of 47 — 13 participants

Back to article view | Back to comp.lang.python


Contents

  Something is rotten in Denmark... harrismh777 <harrismh777@charter.net> - 2011-05-31 01:48 -0500
    Re: Something is rotten in Denmark... Chris Rebert <clp2@rebertia.com> - 2011-05-31 00:00 -0700
    Re: Something is rotten in Denmark... Ian Kelly <ian.g.kelly@gmail.com> - 2011-05-31 01:35 -0600
    Re: Something is rotten in Denmark... Jussi Piitulainen <jpiitula@ling.helsinki.fi> - 2011-05-31 13:08 +0300
      Re: Something is rotten in Denmark... Thomas Rachel <nutznetz-0c1b6768-bfa9-48d5-a470-7603bd3aa915@spamschutz.glglgl.de> - 2011-05-31 12:48 +0200
        Re: Something is rotten in Denmark... Jussi Piitulainen <jpiitula@ling.helsinki.fi> - 2011-05-31 15:15 +0300
    Re: Something is rotten in Denmark... Terry Reedy <tjreedy@udel.edu> - 2011-05-31 13:11 -0400
      Re: Something is rotten in Denmark... harrismh777 <harrismh777@charter.net> - 2011-05-31 15:18 -0500
        Re: Something is rotten in Denmark... Ian Kelly <ian.g.kelly@gmail.com> - 2011-05-31 16:24 -0600
        Re: Something is rotten in Denmark... Terry Reedy <tjreedy@udel.edu> - 2011-05-31 19:14 -0400
          Re: Something is rotten in Denmark... harrismh777 <harrismh777@charter.net> - 2011-05-31 19:09 -0500
            Re: Something is rotten in Denmark... Terry Reedy <tjreedy@udel.edu> - 2011-06-01 13:11 -0400
              Re: Something is rotten in Denmark... harrismh777 <harrismh777@charter.net> - 2011-06-01 19:40 -0500
                Re: Something is rotten in Denmark... harrismh777 <harrismh777@charter.net> - 2011-06-01 19:50 -0500
                  Re: Something is rotten in Denmark... Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2011-06-02 04:37 +0000
                Re: Something is rotten in Denmark... Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2011-06-02 05:14 +0000
                  Re: Something is rotten in Denmark... Chris Angelico <rosuav@gmail.com> - 2011-06-02 18:02 +1000
                  Re: Something is rotten in Denmark... Alain Ketterlin <alain@dpt-info.u-strasbg.fr> - 2011-06-02 13:00 +0200
                    Re: Something is rotten in Denmark... Jussi Piitulainen <jpiitula@ling.helsinki.fi> - 2011-06-02 15:51 +0300
                    Re: Something is rotten in Denmark... Terry Reedy <tjreedy@udel.edu> - 2011-06-02 15:43 -0400
                    Re: Something is rotten in Denmark... Gregory Ewing <greg.ewing@canterbury.ac.nz> - 2011-06-03 11:43 +1200
                      Re: Something is rotten in Denmark... rusi <rustompmody@gmail.com> - 2011-06-02 19:24 -0700
                        Re: Something is rotten in Denmark... Jussi Piitulainen <jpiitula@ling.helsinki.fi> - 2011-06-03 09:17 +0300
                          Re: Something is rotten in Denmark... rusi <rustompmody@gmail.com> - 2011-06-05 03:54 -0700
                            Re: Something is rotten in Denmark... Jussi Piitulainen <jpiitula@ling.helsinki.fi> - 2011-06-05 15:03 +0300
                              Re: Something is rotten in Denmark... rusi <rustompmody@gmail.com> - 2011-06-05 05:26 -0700
                                Re: Something is rotten in Denmark... Jussi Piitulainen <jpiitula@ling.helsinki.fi> - 2011-06-05 16:10 +0300
                      Re: Something is rotten in Denmark... Thomas Rachel <nutznetz-0c1b6768-bfa9-48d5-a470-7603bd3aa915@spamschutz.glglgl.de> - 2011-06-03 10:30 +0200
                        Re: Something is rotten in Denmark... Ian Kelly <ian.g.kelly@gmail.com> - 2011-06-03 11:53 -0600
                      Re: Something is rotten in Denmark... Alain Ketterlin <alain@dpt-info.u-strasbg.fr> - 2011-06-03 12:35 +0200
                        Re: Something is rotten in Denmark... Jussi Piitulainen <jpiitula@ling.helsinki.fi> - 2011-06-03 14:07 +0300
                        Re: Something is rotten in Denmark... harrismh777 <harrismh777@charter.net> - 2011-06-03 15:38 -0500
                        Re: Something is rotten in Denmark... Gregory Ewing <greg.ewing@canterbury.ac.nz> - 2011-06-04 12:40 +1200
                      Re: Something is rotten in Denmark... Nobody <nobody@nowhere.com> - 2011-06-03 14:07 +0100
                  Re: Something is rotten in Denmark... harrismh777 <harrismh777@charter.net> - 2011-06-02 10:44 -0500
                  Re: Something is rotten in Denmark... harrismh777 <harrismh777@charter.net> - 2011-06-02 10:55 -0500
                    Re: Something is rotten in Denmark... Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2011-06-02 17:22 +0000
                      Re: Something is rotten in Denmark... Ian Kelly <ian.g.kelly@gmail.com> - 2011-06-02 11:43 -0600
                Re: Something is rotten in Denmark... Terry Reedy <tjreedy@udel.edu> - 2011-06-02 02:02 -0400
                  Re: Something is rotten in Denmark... harrismh777 <harrismh777@charter.net> - 2011-06-02 11:02 -0500
    Re: Something is rotten in Denmark... Martin Manns <mmanns@gmx.net> - 2011-05-31 23:14 +0200
      Re: Something is rotten in Denmark... Ian Kelly <ian.g.kelly@gmail.com> - 2011-05-31 15:47 -0600
        Re: Something is rotten in Denmark... Martin Manns <mmanns@gmx.net> - 2011-06-01 02:57 +0200
      Re: Something is rotten in Denmark... harrismh777 <harrismh777@charter.net> - 2011-05-31 16:53 -0500
        Re: Something is rotten in Denmark... harrismh777 <harrismh777@charter.net> - 2011-05-31 17:06 -0500
        Re: Something is rotten in Denmark... Chris Angelico <rosuav@gmail.com> - 2011-06-01 08:39 +1000
        Re: Something is rotten in Denmark... Chris Angelico <rosuav@gmail.com> - 2011-06-01 08:40 +1000

Page 2 of 3 — ← Prev page 1 [2] 3  Next page →


#6898

FromGregory Ewing <greg.ewing@canterbury.ac.nz>
Date2011-06-03 11:43 +1200
Message-ID<94qlhsFkriU1@mid.individual.net>
In reply to#6854
Alain Ketterlin wrote:
> But going against generally accepted semantics should at least
> be clearly indicated. Lambda is one of the oldest computing abstraction,
> and they are at the core of any functional programming language.

Yes, and Python's lambdas behave exactly the *same* way as
every other language's lambdas in this area. Changing it to
do early binding would be "going against generally accepted
semantics".

It's not the lambda that's different from other languages,
it's the for-loop. In languages that encourage a functional
style of programming, the moral equivalent of a for-loop is
usually some construct that results in a new binding of the
control variable each time round, so the problem doesn't
arise very often.

If anything should be changed here, it's the for-loop, not
lambda.

-- 
Greg

[toc] | [prev] | [next] | [standalone]


#6903

Fromrusi <rustompmody@gmail.com>
Date2011-06-02 19:24 -0700
Message-ID<238bf9b2-fa07-4da3-b7a0-3bf07a6bd947@q12g2000prb.googlegroups.com>
In reply to#6898
On Jun 3, 4:43 am, Gregory Ewing <greg.ew...@canterbury.ac.nz> wrote:
> Alain Ketterlin wrote:
> > But going against generally accepted semantics should at least
> > be clearly indicated. Lambda is one of the oldest computing abstraction,
> > and they are at the core of any functional programming language.
>
> Yes, and Python's lambdas behave exactly the *same* way as
> every other language's lambdas in this area. Changing it to
> do early binding would be "going against generally accepted
> semantics".
>
> It's not the lambda that's different from other languages,
> it's the for-loop. In languages that encourage a functional
> style of programming, the moral equivalent of a for-loop is
> usually some construct that results in a new binding of the
> control variable each time round, so the problem doesn't
> arise very often.
>
> If anything should be changed here, it's the for-loop, not
> lambda.
>
> --
> Greg

I also thought so

So I tried:
Recast the comprehension as a map
Rewrite the map into a fmap (functionalmap) to create new bindings

def fmap(f,lst):
    if not lst: return []
    return [f(lst[0])] + fmap(f, lst[1:])

Still the same effects.

Obviously I am changing it at the wrong place...

[toc] | [prev] | [next] | [standalone]


#6916

FromJussi Piitulainen <jpiitula@ling.helsinki.fi>
Date2011-06-03 09:17 +0300
Message-ID<qotd3ivtp5k.fsf@ruuvi.it.helsinki.fi>
In reply to#6903
rusi writes:

> So I tried:
> Recast the comprehension as a map
> Rewrite the map into a fmap (functionalmap) to create new bindings
> 
> def fmap(f,lst):
>     if not lst: return []
>     return [f(lst[0])] + fmap(f, lst[1:])
> 
> Still the same effects.
> 
> Obviously I am changing it at the wrong place...

   >>> fs = [(lambda n : n + i) for i in range(10)]
   >>> [f(1) for f in fs]
   [10, 10, 10, 10, 10, 10, 10, 10, 10, 10]

   >>> fs = list(map(lambda i : lambda n : n + i, range(10)))
   >>> list(map(lambda f : f(1), fs))
   [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

[toc] | [prev] | [next] | [standalone]


#7042

Fromrusi <rustompmody@gmail.com>
Date2011-06-05 03:54 -0700
Message-ID<8b46f9a0-1b32-42cb-9f02-a520ae5ca787@r35g2000prj.googlegroups.com>
In reply to#6916
On Jun 3, 11:17 am, Jussi Piitulainen <jpiit...@ling.helsinki.fi>
wrote:
> rusi writes:
> > So I tried:
> > Recast the comprehension as a map
> > Rewrite the map into a fmap (functionalmap) to create new bindings
>
> > def fmap(f,lst):
> >     if not lst: return []
> >     return [f(lst[0])] + fmap(f, lst[1:])
>
> > Still the same effects.
>
> > Obviously I am changing it at the wrong place...
>
>    >>> fs = [(lambda n : n + i) for i in range(10)]
>    >>> [f(1) for f in fs]
>    [10, 10, 10, 10, 10, 10, 10, 10, 10, 10]
>
>    >>> fs = list(map(lambda i : lambda n : n + i, range(10)))
>    >>> list(map(lambda f : f(1), fs))
>    [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

Thanks Jussi for that code -- but I am not fully able to wrap my head
around it.

Is the problem in the lambda? ZF?
Are you trying to say that map works (functionally) and ZF is
imperative?

[toc] | [prev] | [next] | [standalone]


#7044

FromJussi Piitulainen <jpiitula@ling.helsinki.fi>
Date2011-06-05 15:03 +0300
Message-ID<qotr578bi49.fsf@ruuvi.it.helsinki.fi>
In reply to#7042
rusi writes:
> On Jun 3, 11:17 am, Jussi Piitulainen wrote:
> > rusi writes:
> > > So I tried:
> > > Recast the comprehension as a map
> > > Rewrite the map into a fmap (functionalmap) to create new bindings
> >
> > > def fmap(f,lst):
> > >     if not lst: return []
> > >     return [f(lst[0])] + fmap(f, lst[1:])
> >
> > > Still the same effects.
> >
> > > Obviously I am changing it at the wrong place...
> >
> >    >>> fs = [(lambda n : n + i) for i in range(10)]
> >    >>> [f(1) for f in fs]
> >    [10, 10, 10, 10, 10, 10, 10, 10, 10, 10]
> >
> >    >>> fs = list(map(lambda i : lambda n : n + i, range(10)))
> >    >>> list(map(lambda f : f(1), fs))
> >    [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
> 
> Thanks Jussi for that code -- but I am not fully able to wrap my head
> around it.

Oops, sorry, I seem to have edited out a question that I meant to ask.
The question was this: How do -you- write the list comprehension in
terms of your fmap? What -is- the expression that still has the same
effects? That is, where do you bind the i's?

The obvious-to-me way is shown above, but there it is the outer lambda
that establishes the distinct i's for the different closures.

(The composition list(map(...)) works in both versions of Python.)

> Is the problem in the lambda? ZF?
> Are you trying to say that map works (functionally) and ZF is
> imperative?

Sorry, what is ZF?

I'm saying that your fmap works, but in itself it does not provide the
bindings that we are talking about, and you didn't show what does. The
outer lambda in my example does that.

The Python list comprehension [... for i in ...] binds (or assigns to)
just one i which is shared by all the closures above. They end up
having the same value for i because it's the same i.

I hope this is less obscure now.

[toc] | [prev] | [next] | [standalone]


#7045

Fromrusi <rustompmody@gmail.com>
Date2011-06-05 05:26 -0700
Message-ID<cec48785-d239-46d5-9a24-5a9c892bce77@y27g2000prb.googlegroups.com>
In reply to#7044
On Jun 5, 5:03 pm, Jussi Piitulainen <jpiit...@ling.helsinki.fi>
wrote:
> rusi writes:
> > On Jun 3, 11:17 am, Jussi Piitulainen wrote:
> > > rusi writes:
> > > > So I tried:
> > > > Recast the comprehension as a map
> > > > Rewrite the map into a fmap (functionalmap) to create new bindings
>
> > > > def fmap(f,lst):
> > > >     if not lst: return []
> > > >     return [f(lst[0])] + fmap(f, lst[1:])
>
> > > > Still the same effects.
>
> > > > Obviously I am changing it at the wrong place...
>
> > >    >>> fs = [(lambda n : n + i) for i in range(10)]
> > >    >>> [f(1) for f in fs]
> > >    [10, 10, 10, 10, 10, 10, 10, 10, 10, 10]
>
> > >    >>> fs = list(map(lambda i : lambda n : n + i, range(10)))
> > >    >>> list(map(lambda f : f(1), fs))
> > >    [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>
> > Thanks Jussi for that code -- but I am not fully able to wrap my head
> > around it.
>
> Oops, sorry, I seem to have edited out a question that I meant to ask.
> The question was this: How do -you- write the list comprehension in
> terms of your fmap? What -is- the expression that still has the same
> effects? That is, where do you bind the i's?
>
> The obvious-to-me way is shown above, but there it is the outer lambda
> that establishes the distinct i's for the different closures.
>
> (The composition list(map(...)) works in both versions of Python.)
>
> > Is the problem in the lambda? ZF?
> > Are you trying to say that map works (functionally) and ZF is
> > imperative?
>
> Sorry, what is ZF?
>
> I'm saying that your fmap works, but in itself it does not provide the
> bindings that we are talking about, and you didn't show what does. The
> outer lambda in my example does that.
>
> The Python list comprehension [... for i in ...] binds (or assigns to)
> just one i which is shared by all the closures above. They end up
> having the same value for i because it's the same i.
>
> I hope this is less obscure now.

I was wondering why the list(...
Now I see that map returns normal lists in python2 and some generator-
like-thing in 3
I would have said: Shall we just stick to 2 (for this discussion) but
then 2 seems to have a double error that self-corrects this example...

OOOOFFF -- too many variables...

[ZF is Zermelo-Fraenkel -- old name for list comprehension  -- I guess
my age leaks like python's ZF (sorry comprehension) :-) ]

Anyway... My (summary,tentative) conclusion is that python's
comprehensions leak.
The one leak fixed in python3 has not fixed the other (revealed in
this thread)

All this has little to do with lambda (whose scope rules were fixed
around python 2.2 IIRC)

I'd be interested in ur take on this...

[toc] | [prev] | [next] | [standalone]


#7048

FromJussi Piitulainen <jpiitula@ling.helsinki.fi>
Date2011-06-05 16:10 +0300
Message-ID<qotmxhw5sq2.fsf@ruuvi.it.helsinki.fi>
In reply to#7045
rusi writes:
> On Jun 5, 5:03 pm, Jussi Piitulainen wrote:
> > rusi writes:
> > > On Jun 3, 11:17 am, Jussi Piitulainen wrote:
> > > > rusi writes:
> > > > > So I tried:
> > > > > Recast the comprehension as a map
> > > > > Rewrite the map into a fmap (functionalmap) to create new bindings
> >
> > > > > def fmap(f,lst):
> > > > >     if not lst: return []
> > > > >     return [f(lst[0])] + fmap(f, lst[1:])
> >
> > > > > Still the same effects.
> >
> > > > > Obviously I am changing it at the wrong place...
> >
> > > >    >>> fs = [(lambda n : n + i) for i in range(10)]
> > > >    >>> [f(1) for f in fs]
> > > >    [10, 10, 10, 10, 10, 10, 10, 10, 10, 10]
> >
> > > >    >>> fs = list(map(lambda i : lambda n : n + i, range(10)))
> > > >    >>> list(map(lambda f : f(1), fs))
> > > >    [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
> >
> > > Thanks Jussi for that code -- but I am not fully able to wrap my head
> > > around it.
> >
> > Oops, sorry, I seem to have edited out a question that I meant to ask.
> > The question was this: How do -you- write the list comprehension in
> > terms of your fmap? What -is- the expression that still has the same
> > effects? That is, where do you bind the i's?
> >
> > The obvious-to-me way is shown above, but there it is the outer lambda
> > that establishes the distinct i's for the different closures.
> >
> > (The composition list(map(...)) works in both versions of Python.)
> >
> > > Is the problem in the lambda? ZF?
> > > Are you trying to say that map works (functionally) and ZF is
> > > imperative?
> >
> > Sorry, what is ZF?
> >
> > I'm saying that your fmap works, but in itself it does not provide the
> > bindings that we are talking about, and you didn't show what does. The
> > outer lambda in my example does that.
> >
> > The Python list comprehension [... for i in ...] binds (or assigns to)
> > just one i which is shared by all the closures above. They end up
> > having the same value for i because it's the same i.
> >
> > I hope this is less obscure now.
> 
> I was wondering why the list(...
> Now I see that map returns normal lists in python2 and some generator-
> like-thing in 3
> I would have said: Shall we just stick to 2 (for this discussion) but
> then 2 seems to have a double error that self-corrects this example...
> 
> OOOOFFF -- too many variables...
> 
> [ZF is Zermelo-Fraenkel -- old name for list comprehension  -- I guess
> my age leaks like python's ZF (sorry comprehension) :-) ]

Oh, ok. Zermelo-Fraenkel came to mind, but I didn't know it's been
used as a name for list comprehensions.

> Anyway... My (summary,tentative) conclusion is that python's
> comprehensions leak.
> The one leak fixed in python3 has not fixed the other (revealed in
> this thread)
> 
> All this has little to do with lambda (whose scope rules were fixed
> around python 2.2 IIRC)
> 
> I'd be interested in ur take on this...

I think we agree. I've been saying all along that the perceived
problem is not with the lambda at all but with the way the list
comprehension deals with its variable. (I see that some people
understand the situation correctly but blame the lambda anyway.)

Personally, I like your summary, but I'm enough of an outsider that I
do not want to suggest that there is anything wrong with Python. I
just wish to understand how it works, as with any language that I use.

The issue of this thread seems to turn up repeatedly, but is there a
problem with the language mechanisms, is there a problem with the ways
we talk about the language, or is this just the case where people need
to be educated? I'm not sure.

(Incidentally, I'm so new to Python that I started right with 3.0. I
use some 2.4, 2.5-ish a little because software on a certain server is
not kept updated, but I never knew 2.2.)

[toc] | [prev] | [next] | [standalone]


#6927

FromThomas Rachel <nutznetz-0c1b6768-bfa9-48d5-a470-7603bd3aa915@spamschutz.glglgl.de>
Date2011-06-03 10:30 +0200
Message-ID<isa62l$5uu$1@r03.glglgl.eu>
In reply to#6898
Am 03.06.2011 01:43 schrieb Gregory Ewing:

> It's not the lambda that's different from other languages,
> it's the for-loop. In languages that encourage a functional
> style of programming, the moral equivalent of a for-loop is
> usually some construct that results in a new binding of the
> control variable each time round, so the problem doesn't
> arise very often.
>
> If anything should be changed here, it's the for-loop, not
> lambda.

In my opinion, it is rather the closure thing which confused me at some 
time, and that's exactly what is the subject of the thread.


On one hand, a closure can be quite handy because I have access to an 
"outer" vaiable even it changes.

But on the other hand, I might want to have exactly the value the 
variable had when defining the function. So there should be a way to 
exactly do so:

funcs=[]
for i in range(100):
   def f(): return i
   funcs.append(f)

for f in funcs: f()

Here, i should not be transported as "look what value i will get", but 
"look what value i had when defining the function".

So there should be a way to replace the closure of a function with a 
snapshot of it at a certain time. If there was an internal function with 
access to the readonly attribute func_closure and with the capability of 
changing or creating a cell object and thus hbeing capable of doing so, 
it could be used a a decorator for a function to be "closure-snapshotted".

So in

funcs=[]
for i in range(100):
   @closure_snapshot
   def f(): return i
   funcs.append(f)

each f's closure content cells would just be changed not to point to the 
given variables, but to a cell referenced nowhere else and initialized 
with the reference pointed to by the original cells at the given time.


Thomas

[toc] | [prev] | [next] | [standalone]


#6958

FromIan Kelly <ian.g.kelly@gmail.com>
Date2011-06-03 11:53 -0600
Message-ID<mailman.2436.1307123618.9059.python-list@python.org>
In reply to#6927
On Fri, Jun 3, 2011 at 2:30 AM, Thomas Rachel
<nutznetz-0c1b6768-bfa9-48d5-a470-7603bd3aa915@spamschutz.glglgl.de>
wrote:
> So there should be a way to replace the closure of a function with a
> snapshot of it at a certain time. If there was an internal function with
> access to the readonly attribute func_closure and with the capability of
> changing or creating a cell object and thus hbeing capable of doing so, it
> could be used a a decorator for a function to be "closure-snapshotted".
>
> So in
>
> funcs=[]
> for i in range(100):
>  @closure_snapshot
>  def f(): return i
>  funcs.append(f)
>
> each f's closure content cells would just be changed not to point to the
> given variables, but to a cell referenced nowhere else and initialized with
> the reference pointed to by the original cells at the given time.

For CPython 3.2:

import functools
import types

def makecell(value):
    def f():
        return value
    return f.__closure__[0]

def closure_snapshot(f):
    if f.__closure__:
        snapshot = tuple(makecell(cell.cell_contents) for cell in f.__closure__)
    else:
        snapshot = f.__closure__
    g = types.FunctionType(f.__code__, f.__globals__.copy(), f.__name__,
                           f.__defaults__, snapshot)
    functools.update_wrapper(g, f, functools.WRAPPER_ASSIGNMENTS +
                                ('__kwdefaults__',))
    return g

>>> funcs = []
>>> for i in range(10):
...   @closure_snapshot
...   def f(): return i
...   funcs.append(f)
...
>>> [f() for f in funcs]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> funcs = [closure_snapshot(lambda: i) for i in range(10)]
>>> [f() for f in funcs]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]


It doesn't really seem any more straightforward to me than the "i=i"
trick.  Also, I don't know how portable this is to different Python
implementations or future versions.  Finally, note that in order to
make this work correctly in all cases (such as the first example
above, where i is a global, not a cell) we have to snapshot the
globals as well, which could cause further confusion.

Cheers,
Ian

[toc] | [prev] | [next] | [standalone]


#6933

FromAlain Ketterlin <alain@dpt-info.u-strasbg.fr>
Date2011-06-03 12:35 +0200
Message-ID<87vcwnqk2j.fsf@dpt-info.u-strasbg.fr>
In reply to#6898
Gregory Ewing <greg.ewing@canterbury.ac.nz> writes:

> Alain Ketterlin wrote:
>> But going against generally accepted semantics should at least
>> be clearly indicated. Lambda is one of the oldest computing abstraction,
>> and they are at the core of any functional programming language.
>
> Yes, and Python's lambdas behave exactly the *same* way as
> every other language's lambdas in this area. Changing it to
> do early binding would be "going against generally accepted
> semantics".

You must be kidding. Like many others, you seem to think that Scheme is
a typical functional language, which it is not. Learn about ML (i.e.,
SML or CaML), Erlang, Haskell, etc. You can read, e.g.,
http://en.wikipedia.org/wiki/Closure_%28computer_science%29

The reason why we have the kind of lambdas we have in python (and
scheme, and javascript, etc.) is just that it is way easier to
implement. That's all I've said. And people have gotten used to it,
without ever realizing they are using something completely different
from what Church called the "lambda abstraction".

Whether the python/... concept of lambda is useful or not is another,
subjective question, that I'm not intersted in. If you're pleased with
it, go ahead.

(End of discussion for me.)

-- Alain.

[toc] | [prev] | [next] | [standalone]


#6936

FromJussi Piitulainen <jpiitula@ling.helsinki.fi>
Date2011-06-03 14:07 +0300
Message-ID<qot7h93qikx.fsf@ruuvi.it.helsinki.fi>
In reply to#6933
Alain Ketterlin writes:
> Gregory Ewing writes:
> 
> > Alain Ketterlin wrote:
> >> But going against generally accepted semantics should at least be
> >> clearly indicated. Lambda is one of the oldest computing
> >> abstraction, and they are at the core of any functional
> >> programming language.
> >
> > Yes, and Python's lambdas behave exactly the *same* way as every
> > other language's lambdas in this area. Changing it to do early
> > binding would be "going against generally accepted semantics".
> 
> You must be kidding. Like many others, you seem to think that Scheme is
> a typical functional language, which it is not. Learn about ML (i.e.,
> SML or CaML), Erlang, Haskell, etc. You can read, e.g.,
> http://en.wikipedia.org/wiki/Closure_%28computer_science%29

That seems a good read, but I don't see how it supports your
contention that Python goes against generally accepted semantics.

> The reason why we have the kind of lambdas we have in python (and
> scheme, and javascript, etc.) is just that it is way easier to
> implement. That's all I've said. And people have gotten used to it,
> without ever realizing they are using something completely different
> from what Church called the "lambda abstraction".

Church did not deal with assignment statements and order of execution.
Python has to.

> Whether the python/... concept of lambda is useful or not is another,
> subjective question, that I'm not intersted in. If you're pleased with
> it, go ahead.
> 
> (End of discussion for me.)

Oh well.

[toc] | [prev] | [next] | [standalone]


#6970

Fromharrismh777 <harrismh777@charter.net>
Date2011-06-03 15:38 -0500
Message-ID<gDbGp.1$9l.0@newsfe08.iad>
In reply to#6933
Alain Ketterlin wrote:
> The reason why we have the kind of lambdas we have in python (and
> scheme, and javascript, etc.) is just that it is way easier to
> implement. That's all I've said. And people have gotten used to it,
> without ever realizing they are using something completely different
> from what Church called the "lambda abstraction".
>

    This is why I'm willing to accept Terry's 'hypnotized' 
accreditation. The term 'lambda' carries some baggage with it that 
python has chosen to ignore. Using the term 'lambda' as short-hand for 
'an easier way to code in-line functions' causes some of the hypnotizing 
effect, and much of the misunderstanding.

    Frankly, having thought this over for several days, I am now 
convinced the the issue at hand is two-fold:  1) the closure should 
provide option(s) for snap-shot, and 2) the lambda should be implemented 
in a 'purely' functional way or eliminated... if eliminated another 
synonym could be invented to represent in-line function short-hand.

    This is clearing up for me... but probably just beginning to simmer 
for others.


kind regards,
m harris

[toc] | [prev] | [next] | [standalone]


#6989

FromGregory Ewing <greg.ewing@canterbury.ac.nz>
Date2011-06-04 12:40 +1200
Message-ID<94td8nFdpkU1@mid.individual.net>
In reply to#6933
Alain Ketterlin wrote:

> You must be kidding. Like many others, you seem to think that Scheme is
> a typical functional language, which it is not.

I never said that Scheme is a functional language -- I'd be
the first to acknowledge that it's not. I do know what real
functional languages are like.

However, Scheme is more relevant to this discussion than
Haskell, precisely because it's *not* purely functional --
it does allow existing bindings to be changed. Yet its
lambdas are late-binding, and nobody seems to get tripped
up by that they way they do in Python.

Why not? It's because Scheme encourages a style of programming
which favours creation of new bindings rather than changing
existing ones, so most of the time the bindings captured by
a lambda don't change later.

-- 
Greg

[toc] | [prev] | [next] | [standalone]


#6941

FromNobody <nobody@nowhere.com>
Date2011-06-03 14:07 +0100
Message-ID<pan.2011.06.03.13.07.40.156000@nowhere.com>
In reply to#6898
On Fri, 03 Jun 2011 11:43:54 +1200, Gregory Ewing wrote:

>> But going against generally accepted semantics should at least
>> be clearly indicated. Lambda is one of the oldest computing abstraction,
>> and they are at the core of any functional programming language.
> 
> Yes, and Python's lambdas behave exactly the *same* way as
> every other language's lambdas in this area. Changing it to
> do early binding would be "going against generally accepted
> semantics".

In Lisp, it depends upon whether the free variable is bound:

	$ clisp
	[1]> (setq f (lambda (x) (+ x i)))
	#<FUNCTION :LAMBDA (X) (+ X I)>
	[2]> (setq i 7)
	7
	[3]> (apply f (list 4))
	11
	[4]> (setq i 12)
	12
	[5]> (apply f (list 4))
	16
	^D
	$ clisp
	[1]> (let ((i 7)) (setq f (lambda (x) (+ x i))))
	#<FUNCTION :LAMBDA (X) (+ X I)>
	[2]> (apply f (list 4))
	11
	[3]> (setq i 12)
	12
	[4]> (apply f (list 4))
	11
	^D

If the variable is bound, then the lambda creates a closure.

And Python behaves the same way:

	> f = (lambda i: lambda x: x + i)(7)
	> f(4)
	11
	> i = 12
	> f(4)
	11

	# If you really want a "let", this syntax is closer:
	# f = (lambda i = 7: lambda x: x + i)()

The original semantics (from the lambda calculus) don't deal with the
concept of mutable state.

> If anything should be changed here, it's the for-loop, not lambda.

Right. The for loop should bind the variable rather than set it.

[toc] | [prev] | [next] | [standalone]


#6867

Fromharrismh777 <harrismh777@charter.net>
Date2011-06-02 10:44 -0500
Message-ID<5dOFp.25708$oq.13740@newsfe17.iad>
In reply to#6839
Steven D'Aprano wrote:
> funcs = [(lambda x, i=j: x+i) for j in range(10)]
>
> Now the reader is no longer distracted by the "i=i" ugliness.

    That's a good idea, in fact, change made!

> The problem with Do What I Mean is that it so rarely Does What You Mean.
> At best it Does What Some Other Guy Imagined I'd Probably Mean In This
> Situation. Let's not go there.

    Oh, I agree. This is one of those things where I agree 
(tongue-in-cheek) in all cases except the one I'm whining about!   :)

  --just kidding, here.  Yes, ambiguous is bad.

[toc] | [prev] | [next] | [standalone]


#6869

Fromharrismh777 <harrismh777@charter.net>
Date2011-06-02 10:55 -0500
Message-ID<9oOFp.2056$Zp6.1700@newsfe19.iad>
In reply to#6839
Steven D'Aprano wrote:
> What do you expect this code to do?
>
> a = 42
> funcs = [(lambda x: x+a) for i in range(10)]
> funcs[0](1)

    I do see your point with this... truly... but it did get me to think 
about what I *do* expect... and that is that 'a' (for the lambda) will 
be whatever 'a' is (now) at the time when the anonymous function is 
returned, not later when it is called (not really). If I understand 
things correctly, if 'a' references a different simple int object 
'later' (before the anonymous function is called) then the result of the 
lambda may not be what was expected. In your example, of course, the 'i' 
is not relevant.  On the other hand, as in callbacks, the whole reason 
we want to use the lambda in the first place is because we don't know 
what the data will be 'later,' and in fact we really do want 
'late-binding' after all.  (I guess, I want my cake on a nice china 
saucer, with a silver spoon, 'and' I want to eat it too... )  'magine that!

    I know, you're saying "well, duh".  But here's the thing... that's 
the beauty and the curse of pure functional programming (like haskell) 
which (by the way) doesn't have this problem, because doesn't have 
mutables as in Python ( nor other languages, non functional ). So, those 
of us attempting to morph functional programming over python are having 
a little difficulty because what we expect to happen with the lambda in 
a list comprehension is adversely affected by our misunderstanding of 
python's 'late-binding'. See the whine, here?



kind regards,
m harris

[toc] | [prev] | [next] | [standalone]


#6874

FromSteven D'Aprano <steve+comp.lang.python@pearwood.info>
Date2011-06-02 17:22 +0000
Message-ID<4de7c6e7$0$29996$c3e8da3$5496439d@news.astraweb.com>
In reply to#6869
On Thu, 02 Jun 2011 10:55:49 -0500, harrismh777 wrote:

> Steven D'Aprano wrote:
>> What do you expect this code to do?
>>
>> a = 42
>> funcs = [(lambda x: x+a) for i in range(10)] funcs[0](1)
> 
>     I do see your point with this... truly... but it did get me to think
> about what I *do* expect... and that is that 'a' (for the lambda) will
> be whatever 'a' is (now) at the time when the anonymous function is
> returned, not later when it is called (not really).

Arguably, there's nothing wrong with early binding as a strategy. It's 
just a different strategy from late binding.

It seems to me that early binding is less flexible than late, because 
with late binding you have a chance to simulate early binding by saving a 
reference of the variable elsewhere, such as in a default value, or an 
instance attribute. But with early binding, you're stuck. There's no 
simple or straightforward way to simulate late binding in an early 
binding language.



-- 
Steven

[toc] | [prev] | [next] | [standalone]


#6876

FromIan Kelly <ian.g.kelly@gmail.com>
Date2011-06-02 11:43 -0600
Message-ID<mailman.2394.1307036619.9059.python-list@python.org>
In reply to#6874
On Thu, Jun 2, 2011 at 11:22 AM, Steven D'Aprano
<steve+comp.lang.python@pearwood.info> wrote:
> It seems to me that early binding is less flexible than late, because
> with late binding you have a chance to simulate early binding by saving a
> reference of the variable elsewhere, such as in a default value, or an
> instance attribute. But with early binding, you're stuck. There's no
> simple or straightforward way to simulate late binding in an early
> binding language.

Well, you can always do something like this:

>>> a = box(42)
>>> func = lambda x: a.value + x
>>> func(1)
43
>>> a.value = 6 * 9
>>> func(1)
55

I realize that's not exactly the same thing since you're stuck working
with "a.value" instead of just "a", but it does produce the desired
result.

Cheers,
Ian

[toc] | [prev] | [next] | [standalone]


#6841

FromTerry Reedy <tjreedy@udel.edu>
Date2011-06-02 02:02 -0400
Message-ID<mailman.2381.1306994558.9059.python-list@python.org>
In reply to#6828
On 6/1/2011 8:40 PM, harrismh777 wrote:

> The part that I don't see much about in the docs (some books, that is)
> is that the lambda lookups occur late (the lambda is evaluated at the
> time it is called). The Python docs on-line *do say* this (I found too
> late) but its one quick phrase that can be missed. So, the i in
> range(10) is sitting there at '9' by the time *any* of the ten lambdas
> get called. This is not intuitive, nor good. IMHO

I readily admit that the docs might be improved. Part of the reason I 
spend time responding to issues like this is to practive giving 
explanations that I might use in my own writings or even in the doc. I 
have at least one small idea already.

> Yes, I can explicitly grab each 'i' as it flies by with a little clever
> coding of the default value for the lambda n, i=i: i + n but that
> 'trick' is not intuitive, nor is it clear reading. It 'works' is just
> about all one can say for it (not very elegant).

You found the alternative of using a closure (the g(i) that returns a 
*new* function for each i). You happened to use lambda to create each 
new function; a nested def statement would have served just as well. 
Replacing the default arg trick was one of the reasons to introduce 
closures (in about 2.3). It might be considered the recommended solution 
to this use case.

> work. I'm wondering if whether it would make some sense to put some
> 'binding smarts' into the interpreter to allow for 'interpreter
> intuition' (say AI ) that would presume to understand when early vs late
> binding makes sense and apply early binding in those cases where the
> context is not ambiguous and when it is clear that an iterable is being
> passed to the constant lambda function?

Oh the irony of this proposal. You scolded us for breaking code with 2 
to 3 changes, and here you propose a change more radical than anything 
done in Python 3, and certain to break code, introduce bugs, complicate 
the language, and reduce its functionality. Most of Guido's design 
decision are rejections of such changes ;-).

-- 
Terry Jan Reedy

[toc] | [prev] | [next] | [standalone]


#6870

Fromharrismh777 <harrismh777@charter.net>
Date2011-06-02 11:02 -0500
Message-ID<CuOFp.39468$Vp.19473@newsfe14.iad>
In reply to#6841
Terry Reedy wrote:
> Oh the irony of this proposal. You scolded us for breaking code with 2
> to 3 changes, and here you propose a change more radical than anything
> done in Python 3, and certain to break code, introduce bugs, complicate
> the language, and reduce its functionality. Most of Guido's design
> decision are rejections of such changes ;-).

    Yeah, I knew that was coming...   and I deserved it too!   :)

    Yes, I'm torn a bit over this surprise. Because I really don't want 
anything like ambiguous AI intuitions going on in the interpreter... its 
just me whining out loud and realizing that explicit really is better 
than implicit... much of the time.


kind regards,
m harris

[toc] | [prev] | [next] | [standalone]


Page 2 of 3 — ← Prev page 1 [2] 3  Next page →

Back to top | Article view | comp.lang.python


csiph-web