Would Anonymous Functions Help in Learning Programming/Python?

S

Steven D'Aprano

True, there is lambda, but that is very limited. It might be useful for
key arguments, but not much else.

No, lambda is useful for anything that any other function is useful for,
provided that you can write it as a single expression and not need to use
statements. In other words, a lambda function can do anything anything
any other function can, just less conveniently.

(To pick one example at random, you can use print with lambda:
http://northernplanets.blogspot.com/2006/07/python-using-print-with-lambda.html
and while it is easy it isn't exactly convenient.)

And that's basically why function definitions have the syntax they do,
because trying to hammer a multi-line function definition into a single
expression is painful.

It doesn't solve the teaching problem
of "See, functions are just like any other data type. You can assign it
to a variable."


Is their interactive interpreter broken?

.... return "I'm a parrot with %s plumage." % colour
...."I'm a parrot with green plumage."


Or using lambda:

"I'm a parrot with purple plumage."


It would be a footnote if it's mentioned at all. My hope
is to subtly reinforce the notion that functions are data and can be
passed around. The current function declaration doesn't help with this.

Some things just need to be learnt. I'm in favour of making languages
easy for newbies to learn, but making function and method definitions
harder to use just so newbies will be given a subtle reminder of
something that 80% of them will never notice or use anyway is a bad
trade-off.

Creating a function and assigning it to a name is exactly what Python
does, why not have it come out in the syntax? It's not necessary, yes,
but I think it would be helpful for teaching purposes.

If people don't get it when you EXPLICITLY show them that functions are
first-class objects, how do you expect them to notice it on their own
based on the IMPLICIT similarities in syntax?
 
S

Scott David Daniels

Here's an idea:

import math

def sin_integral(start, finish, dx):
total = 0.0
y0 = math.sin(start)
for n in range(1, 1 + int((finish - start) / float(dx))):
y1 = math.sin(start + n * dx)
total += (y0 + y1)
y0 = y1
return total / 2. * dx


def cos_integral(start, finish, dx):
total = 0.0
y0 = math.sin(start)
for n in range(1, 1 + int((finish - start) / float(dx))):
y1 = math.cos(start + n * dx)
total += (y0 + y1)
y0 = y1
return total / 2. * dx

generalize and separate the integration technique from the
function it integrates.
 
M

Marc 'BlackJack' Rintsch

First of all, let me say that I think "functions as first class data" is
helpful, but not crucial, to programming in Python, and there are many
people who simply don't need the lesson. Especially someone like an
engineer (in the classical sense), who isn't building versatile software
packages, won't need to resort to functional programming much.

Of course you don't *need* functional programming as in "there's no way
around it", but why are engineers such an exception!? I find the stuff in
`itertools` very handy when it comes to filter, manipulate, group and
aggregate data from large log files in ad hoc scripts. I'm not an
engineer but I guess there are similar tasks with log files or measurement
results.
For straightforward tasks, like sorting lists with a custom ordering,
functional progamming merely a convenience, and can be done without.

``for`` loops are just a convenience, you can do without. ;-)

Ciao,
Marc 'BlackJack' Rintsch
 
K

Kay Schluehr

Yeah, I agree, that does look pretty ugly. Correct me if I'm wrong,
but I thought the way Python determines a block is by the whitespace
of the first line. So, as long as the spacing (or !tabbing!) is
consistent from line to line the parser will know it's part of the
same block. From that I don't think the parser would have much trouble
extracting the function definition from the above example. I would
change the word "def". That's never been informative enough for me.

Here is the grammar:

http://svn.python.org/projects/stackless/tags/python-2.5/Grammar/Grammar

If you feel you can transform it into another unambigous grammar
mixing statements and expressions it's up to you. Guido at least does
not seem to show interest:

http://www.artima.com/weblogs/viewpost.jsp?thread=147358

When you are working on it you'll need a parser generator that also
checks your changes.
EasyExtend might help

http://www.fiber-space.de/EasyExtend/doc/EE.html

You can use it with Python 2.5, create a new fiber and a Grammar.ext
file. Note that the parser generator is LL(1) so it is not all
powerfull but *very* efficient. Tokenization is performed separately.
INDENT, DEDENT are indentation token used within the definition of the
suite nonterminal. I'd provide additional help when you get stuck.

Finally the standard response to your claims: "this is all open
source". This advice might be annoying and uncomfortable and maybe you
just want to talk about some problems and make a few guesses instead
of solving them actually. We are all Web 2.0 now and discussing issues
and doing socialization might be more important than everything else
even among geeks. This can be confusing however for people who believe
that softskills are not everything.

Regards, Kay
 
P

Paul Rubin

Kay Schluehr said:
If you feel you can transform it into another unambigous grammar
mixing statements and expressions it's up to you.

We got rid of the print statement for python 3.0. Why not get rid
of the rest of them too? Just use expressions for everything, as
works fine for plenty of other languages.
 
R

Ron Adam

Scott said:
Here's an idea:

import math

def sin_integral(start, finish, dx):
total = 0.0
y0 = math.sin(start)
for n in range(1, 1 + int((finish - start) / float(dx))):
y1 = math.sin(start + n * dx)
total += (y0 + y1)
y0 = y1
return total / 2. * dx


def cos_integral(start, finish, dx):
total = 0.0
y0 = math.sin(start)
for n in range(1, 1 + int((finish - start) / float(dx))):
y1 = math.cos(start + n * dx)
total += (y0 + y1)
y0 = y1
return total / 2. * dx

generalize and separate the integration technique from the
function it integrates.


How about this?

It's based on the apple basic program example in How to Enjoy Calculus.


Ron




import math

def integrate(fn, x1, x2, n=100):
# Calculate area of fn using Simpson's rule.
width = float(x2 - x1) / n
area = fn(x1)
if n % 2 != 0: # make sure its even
n += 1
for n in range(1, n):
x = x1 + n * width
if n % 2 == 0:
area += 2.0 * fn(x)
else:
area += 4.0 * fn(x)
area += fn(x2)
return area * (width / 3.0)


def fn(x):
return x**2

print "Area of fn:", integrate(fn, 0, 2)

print "Area of cos fn:", integrate(math.cos, 1, 2)

print "Area of sin fn:", integrate(math.sin, 1, 2)




Area of fn: 2.66666666667
Area of cos fn: 0.0678264420216
Area of sin fn: 0.956449142468
 
R

Ron Adam

Scott said:
Here's an idea:

import math

def sin_integral(start, finish, dx):
total = 0.0
y0 = math.sin(start)
for n in range(1, 1 + int((finish - start) / float(dx))):
y1 = math.sin(start + n * dx)
total += (y0 + y1)
y0 = y1
return total / 2. * dx


def cos_integral(start, finish, dx):
total = 0.0
y0 = math.sin(start)
for n in range(1, 1 + int((finish - start) / float(dx))):
y1 = math.cos(start + n * dx)
total += (y0 + y1)
y0 = y1
return total / 2. * dx

generalize and separate the integration technique from the
function it integrates.


How about this?

It's based on the apple basic program example in How to Enjoy Calculus.


Ron




import math

def integrate(fn, x1, x2, n=100):
# Calculate area of fn using Simpson's rule.
width = float(x2 - x1) / n
area = fn(x1)
if n % 2 != 0: # make sure its even
n += 1
for n in range(1, n):
x = x1 + n * width
if n % 2 == 0:
area += 2.0 * fn(x)
else:
area += 4.0 * fn(x)
area += fn(x2)
return area * (width / 3.0)


def fn(x):
return x**2

print "Area of fn:", integrate(fn, 0, 2)

print "Area of cos fn:", integrate(math.cos, 1, 2)

print "Area of sin fn:", integrate(math.sin, 1, 2)




Area of fn: 2.66666666667
Area of cos fn: 0.0678264420216
Area of sin fn: 0.956449142468
 
K

Kay Schluehr

We got rid of the print statement for python 3.0. Why not get rid
of the rest of them too? Just use expressions for everything, as
works fine for plenty of other languages.

One might create a new dynamic functional+OO programming language,
where small statements like print, assert, raise etc. all become
functions and statements like while, for, with etc. become anonymous
closures. I think Logix had gone once in this direction but was
abandoned due to severe technical problems. So one might eventually
revive this project with another more sound technical base. Personally
I'm not sure it's worth a large effort and whether EasyExtend is the
right toolkit at hand. So it's definitely not Guido who will revive it
and also not me. Maybe some PyPy guys? What are we talking about -
really?
 
M

Marc 'BlackJack' Rintsch

One might create a new dynamic functional+OO programming language,
where small statements like print, assert, raise etc. all become
functions and statements like while, for, with etc. become anonymous
closures.

Before someone starts to create such a thing he should take a look at Io
which has just objects and methods.

http://www.iolanguage.com/

Ciao,
Marc 'BlackJack' Rintsch
 
P

Paul Rubin

Carl Banks said:
That's it, lost me already. You ever see the kinds of programs
mechanical engineers write? It isn't software.

They do a lot of number crunching. Certainly they can appreciate
higher order functions like integrate(f, x0, x1) to integrate the
function f from x0 to x1; or diff(f, x0) to find the derivative of f
at x0; etc. Fortran had cheesy ways to do this as far back as the
1950's.
 
K

Kay Schluehr

Before someone starts to create such a thing he should take a look at Io
which has just objects and methods.

http://www.iolanguage.com/

Ciao,
Marc 'BlackJack' Rintsch

I checked out Io once and I disliked it. I expected Io's prototype OO
being just a more flexible variant of class based OO but Io couples a
prototype very closely to its offspring. When A produces B and A.f is
modified after production of B also B.f is modified. A controls the
state of B during the whole lifetime of B. I think parents shall not
do this, not in real life and also not in programming language
semantics.

There was another, similar and also abandoned project a while ago
heading for prototype OO called Prothon:

http://mail.python.org/pipermail/python-announce-list/2004-March/002966.html

When I remember correctly it was killed not because it was too
ambitious but the author lost his vision and didn't want to grow
Prothons ecosystem.
 
C

Carl Banks

They do a lot of number crunching. Certainly they can appreciate higher
order functions like integrate(f, x0, x1) to integrate the function f
from x0 to x1; or diff(f, x0) to find the derivative of f at x0; etc.
Fortran had cheesy ways to do this as far back as the 1950's.

Well, I appreaciate it, as do many other engineers, but for a lot of
engineers functional programming might as well not exist, either because
they don't about it or don't care about it. And it doesn't really affect
them much, other than making them slightly less efficient then they could
have been. That's the key here.


Carl Banks
 
M

Marc 'BlackJack' Rintsch

I checked out Io once and I disliked it. I expected Io's prototype OO
being just a more flexible variant of class based OO but Io couples a
prototype very closely to its offspring. When A produces B and A.f is
modified after production of B also B.f is modified. A controls the
state of B during the whole lifetime of B. I think parents shall not
do this, not in real life and also not in programming language
semantics.

Well it's like Python: inherited slots (attributes) are looked up in the
ancestors. It should be easy to override `Object clone` in Io, so all
slots of the ancestor are shallow copied to the clone, but I guess this
might break existing code. At least for your own code you could introduce
a `realClone` slot.

Ciao,
Marc 'BlackJack' Rintsch
 
K

Kay Schluehr

Well it's like Python: inherited slots (attributes) are looked up in the
ancestors. It should be easy to override `Object clone` in Io, so all
slots of the ancestor are shallow copied to the clone, but I guess this
might break existing code. At least for your own code you could introduce
a `realClone` slot.

Ciao,
Marc 'BlackJack' Rintsch

But in class based OO most relevant attributes are defined during
object construction and they can't be simply changed by setting a
class attribute. Later you often create new attributes as but on
object level. You do not overuse the object/class relationship to
broadcast changes to all objects. While you might override 'Object
clone' I don't believe changing the way how the whole object model
works is a good idea and since it happens on source level you will get
also a performance hit.
 
S

Scott David Daniels

Ron said:
How about this?
It's based on the apple basic program example in How to Enjoy Calculus.
Ron

import math
def integrate(fn, x1, x2, n=100):...
def fn(x): ...
print "Area of fn:", integrate(fn, 0, 2)
print "Area of cos fn:", integrate(math.cos, 1, 2)

The point was a pedagogic suggestion, i.e. "Try taking your
friend along this path." I wasn't trying to do a particularly
good job integrating, simply trying to show how you could
motivate first-class functions by showing a "useful" and
"fun" (at least to an engineer) function that cries out
for higher order functions. In my experience engineers
often want a "reason its useful" before engaging with an
idea. I'll bet that after a few such experiences he'll see
how passing around functions and (later) making functions from
from functions is a great tool to have in his toolbox. Once
he sees that, there will be no problem.

-Scott David Daniels
(e-mail address removed)
 
M

Marc 'BlackJack' Rintsch

But in class based OO most relevant attributes are defined during
object construction and they can't be simply changed by setting a
class attribute. Later you often create new attributes as but on
object level. You do not overuse the object/class relationship to
broadcast changes to all objects.

You don't do this in Io either. It's really like Python in this respect.
There's an `init` slot that gets called by (the default) `clone` and you
set "instance attributes" there, for example mutables so they are not
shared by all clones.

Ciao,
Marc 'BlackJack' Rintsch
 
B

Bryan Olson

There are already anonymous functions in Python.

lambda x, y, z: x + y + z

is the same as:

def _(x, y, z): return x + y + z

They are the same only in special cases:

The special identifier "_" is used in the interactive
interpreter to store the result of the last evaluation; it
is stored in the __builtin__ module. When not in interactive
mode, "_" has no special meaning and is not defined.
[Python Reference Manual; 2.3.2 Reserved classes of
identifiers. http://docs.python.org/ref/id-classes.html]
 
M

Matthew Woodcraft

Cristian said:
To me, the biggest setback for new programmers is the different
syntax Python has for creating functions. Instead of the common (and
easy to grasp) syntax of foo = bar Python has the def foo(): syntax.
[...]

in a program like Python there doesn't seem to be any other reason to
have it.

One reason for the different syntax is that functions, unlike most
other objects, know their own names (which can be shown in tracebacks
and the like).

-M-
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,767
Messages
2,569,571
Members
45,045
Latest member
DRCM

Latest Threads

Top