Would Anonymous Functions Help in Learning Programming/Python?

P

Paul Rubin

Bryan Olson said:
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...

I'm not sure what Chris was really getting at, since among other
things lambda:... is an expression while def... is a statement.
But Python certainly has anonymous functions without lambda:

def compose(f,g):
def h(*a, **k):
return f(g(*a, **k))
return h

x = compose(math.sin, math.cos)(1.0)

computes sin(cos(1.0)) where a function equivalent to
lambda x: sin(cos(x))
is constructed and used without being bound to a symbol.
 
B

Bryan Olson

Cristian said:
[...] Specifically, he's having trouble
thinking of functions as first order data (don't worry, I haven't
confused him with such terminology yet). [...]
And, after we finally
get a hold of first order functions, we appreciate its incorporation
into languages. It would be a shame if my friend just learns the
motions and never incorporates first order functions into his
programs.


The terminology I've heard for this is that functions are
"first-class values". There's a minor name-collision on
"class", but people have heard "first-class" in other
contexts, and it means the same thing here: no second-class
status for such values.

"First order" has other usages, some contradicting what you
mean. First-order functions are exactly those that cannot
take functions as arguments. It would be a shame if your
friend never incorporates *higher order* functions.
[http://en.wikipedia.org/wiki/Higher-order_function]


[...]
my_function = function(foo, bar): pass
an_instance_method = function(self, foo): pass
a_method_declaration = method(self, foo): pass

I just argued for adopting mainstream terminology, but here
I like yours better. The keyword "lambda" sucks. All the
other keywords, having been so carefully chosen to relate
to their conversational usage, have mis-trained to look
at this spelling-out of the name of an arbitrary symbol.

Alonzo Church's calculus used the *symbol*. He just needed
it to be distinct. Could as well have been the '$-calculus'.

Function-as-value is not a trivial concept. I remember
wrestling with it, and I've seen many others do the same.
The 'lambda' keyword is so awful as to pass for deep
mystery long after students have grasped first-class
functions.


"function" would be a much better keyword. Or follow ML and
abbreviate to "fn", or choose another term that clues one
in to the meaning. I'd have caught on much quicker given a
a hint to read:

lambda x, y: x + y

as: "the function of two variables, call them x and y, that
returns x + y."


--Bryan
 
B

Bryan Olson

Paul said:
I'm not sure what Chris was really getting at,

I was big-time unsure. At first, I thought Chris's latter
form to be equivalent to a pass statement. I've long used
the Python convention of assigning throw-away values to '_',
and I was under the mistaken impression Python defined _
as a discard target.

When I looked it up, I was surprised to find that my
understanding of the _ variable was wrong, and shocked that
there really is an interesting context where Chris's claim
has a strong case.

since among other
things lambda:... is an expression while def... is a statement.

True fact, but note that one form of statement is an expression.
But Python certainly has anonymous functions without lambda:

def compose(f,g):
def h(*a, **k):
return f(g(*a, **k))
return h

x = compose(math.sin, math.cos)(1.0)
computes sin(cos(1.0)) where a function equivalent to
lambda x: sin(cos(x))
is constructed and used without being bound to a symbol.

How anonymous is that function when we can see that its name is 'h'?

import math

f = compose(math.sin, math.cos)
print f.__name__

Am I making a bogus argument? Kind of. Most authors of "anonymous"
works do in fact have real names. The term really means that they
entered the context at issue dissociated from their given name.
Nevertheless, def is never a real anonymous function constructor.

If our concern is Python's suitability for studying principles of
programming, I think I'm on stronger ground. Python is great for
getting things done. It is easy to learn in the sense of learning
to to use if for practical tasks. Python's actual semantics are not
as neat and clean as some other languages.
 
P

Paul Rubin

Bryan Olson said:
How anonymous is that function when we can see that its name is 'h'?

h is out of scope after compose returns, so the function is anonymous
in the sense that there is no symbol bound to the function, through
which you can refer to it.
import math

f = compose(math.sin, math.cos)
print f.__name__

I prefer to think of __name__ as just some debugging info stuck inside
the closure, though actually Python is introspective enough to be able
to let you locate and call a function whose __name__ is "h". Of
course there might be more than one:

f = compose(math.sin, math.cos)
g = compose(math.sqrt, math.tan)
print f.__name__, g.__name__
Nevertheless, def is never a real anonymous function constructor.

Well, def constructs a function with a name, but the function can stay
around after the name goes away, after which I'd say the function is
nameless. One could otherwise say that (lambda x: x+x) is not
anonymous either, since id(lambda ...) is a unique label stuck to it
like a __name__.
If our concern is Python's suitability for studying principles of
programming, I think I'm on stronger ground. Python is great for
getting things done. It is easy to learn in the sense of learning
to to use if for practical tasks. Python's actual semantics are not
as neat and clean as some other languages.

Fair enough.
 
E

Erik Max Francis

Kay said:
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.

It sounds like you're talking about some language other than Io, or
didn't delve deeply enough into it, since Io makes no such requirements.

The attribute and method (not made distinct in Io; they're called
"slots") is much the same as with Python; the current instance is
checked for the object, then its parents, then _its_ parents, and so on.
 
S

Steven D'Aprano

Well, def constructs a function with a name, but the function can stay
around after the name goes away, after which I'd say the function is
nameless. One could otherwise say that (lambda x: x+x) is not anonymous
either, since id(lambda ...) is a unique label stuck to it like a
__name__.

If you want to be tediously pedantic, lambda doesn't construct anonymous
functions either: you can bind them to a name, and whether you do or not,
they have a name.
'<lambda>'

It's just that all functions created by lambda share the same name.

If you really want an anonymous function...
.... return 3
....<function at 0x97a26bc>


I know, I know, I'm being tediously pedantic... and that's not what the
anonymity of lambda refers to. What it actually means is that the lambda
doesn't create a name in a namespace. In that regard, calling a factory
function is also anonymous, because the function isn't added to the
calling code's namespace.

Or, to put it another way...

def factory():
def foo():
return 3
return foo


Within factory(), foo() is not an anonymous function, because 'foo' is in
the local namespace. But the result of factory() is anonymous in the same
sense that lambda is: although the function object has a attribute
__name__ set to 'foo', calling factory() doesn't modify the caller's
namespace (unless you assign the result to a name).
 
K

Kay Schluehr

The attribute and method (not made distinct in Io; they're called
"slots") is much the same as with Python; the current instance is
checked for the object, then its parents, then _its_ parents, and so on.

Repeating the same point as Marc doesn't mean that I have to repeat my
reply as well. Doesn't it?
 
R

Ron Adam

Scott said:
The point was a pedagogic suggestion, i.e.

I understood your point. I just found it interesting since I've been
trying to extend my math (for use with python) skills in this area.

"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.

Yes, I agree. Another useful thing I've found is to store functions in a
dictionary and call them (dispatching) based on some data value.

Ron
 
S

Scott David Daniels

Ron said:
I understood your point. I just found it interesting since I've been
trying to extend my math (for use with python) skills in this area.

Ah, sorry. I had realized I wasn't explicit in my first message.
Yes, a perfectly fine integration.

You can then (and this is a major jump to get used to):
import functools

Sine = functools.partial(integrate, math.cos, 0.0, n=100)

Similarly, you can define a derivative that will behave fairly well,
all without examining the definition of the function being operated
upon.

-Scott
 
R

Ron Adam

Scott said:
Ah, sorry. I had realized I wasn't explicit in my first message.

Yes, I wasn't trying to correct you. I'm sorry if it came across that way.

Yes, a perfectly fine integration.

There's still something about it that bothers me. I think it may be the
n=100 rather than delta='.0001', or some other way to specify the minimal
error. (Yes, it's a bit off topic.)

You can then (and this is a major jump to get used to):
import functools

Sine = functools.partial(integrate, math.cos, 0.0, n=100)

I haven't played around with .partial yet. I wonder if it could be used in
dispatching situations where the function signatures differ?

Similarly, you can define a derivative that will behave fairly well,
all without examining the definition of the function being operated
upon.

I'll get around to doing that at some point. ;-)


I also have a class that solves equations that takes a function in a
similar way. It uses the same method used by HP calculators to solve TVM
equations.

Cheers,
Ron
 
R

Ron Adam

Scott said:
Ah, sorry. I had realized I wasn't explicit in my first message.

Yes, I wasn't trying to correct you. I'm sorry if it came across that way.

Yes, a perfectly fine integration.

There's still something about it that bothers me. I think it may be the
n=100 rather than delta='.0001', or some other way to specify the minimal
error. (Yes, it's a bit off topic.)

You can then (and this is a major jump to get used to):
import functools

Sine = functools.partial(integrate, math.cos, 0.0, n=100)

I haven't played around with .partial yet. I wonder if it could be used in
dispatching situations where the function signatures differ?

Similarly, you can define a derivative that will behave fairly well,
all without examining the definition of the function being operated
upon.

I'll get around to doing that at some point. ;-)


I also have a class that solves equations that takes a function in a
similar way. It uses the same method used by HP calculators to solve TVM
equations.

Cheers,
Ron
 
K

Kay Schluehr

Kay Schluehr a écrit :
(snip)




I may totally miss the point, but how is this different from:

class A(object):
def dothis(self):
print "A.dothis(%s)" % self

class B(A):
pass

b = B()

b.dothis()

def dothat(self):
print "function dothat(%s)" % self

A.dothis = dothat
b.dothis()

It's not a big deal because you do not use a class to propagate
mutable state unless you are using a class attribute intentionally ( i
guess you do not overuse it just to avoid object encapsulation and
make everything global ). When using a prototype as in Io you need to
protect the state of the child object yourself. You can do this by
overwriting the objects slots but then you end up writing your own
object constructors and the templates accordingly, also named
"classes" by some. Not having dedicated object constructors, member
variable initializations and the presumed class definition boilerplate
comes at the price of introducing them on your own.

Prototypes have a purpose of course when you want to transfer state to
a newly created object. Using a prototyping mechanism as a generic
form of a copy constructor is the right kind to thinking about them
IMO.

------------

I have got the impression that the discussion has drifted away from
what Paul Rubin suggested, namely abandone the expression/statement
distinction. Instead we are discussing the advantages and
disadvantages of object models now. Can we stop here, please?
 
C

Cristian

Ok, then what about classes ? They also are objects-like-any-other,
after all. So should we have this syntax too ?

MyClass = class(ParentClass):
__init__ = function (self, name):
self.name = name

?-)

For consistency I would suggest this, but Python already does this!

Foo = type('Foo', (object, ), {'bar': lambda self, bar: bar})

I've created a new class and then binded it to name afterwards. If you
can import modules without special syntax and you can create classes
without special syntax, why should functions be treated any
differently?
 
M

Marc 'BlackJack' Rintsch

It's not a big deal because you do not use a class to propagate
mutable state unless you are using a class attribute intentionally ( i
guess you do not overuse it just to avoid object encapsulation and
make everything global ). When using a prototype as in Io you need to
protect the state of the child object yourself.

Just like in Python! Here `things` are shared between all "children":

class A(object):
things = list()

def add(self, thing):
self.things.append(thing)

This is what happens too when you use this Io snippet:

A := Object clone do(
things := list()

add := method(thing,
self things append(thing)
)
)

If you don't want `things` to be shared you write an `init` method, in
both Python and Io. Python:

class B(object):
def __init__(self):
self.things = list()

def add(self, thing):
self.things.append(thing)

And Io:

B := Object clone do(
init := method(
self things := list()
self
)

add := method(thing,
self things append(thing)
)
)

The `init` is called by the default `clone` method automatically just like
`__init__()` in Python. It is really much like the class/instance
relationship in Python with just the line between class and instance
blurred.
You can do this by overwriting the objects slots but then you end up
writing your own object constructors and the templates accordingly, also
named "classes" by some. Not having dedicated object constructors,
member variable initializations and the presumed class definition
boilerplate comes at the price of introducing them on your own.

The mechanism is already there in Io, no need to invent, just use it.

Ciao,
Marc 'BlackJack' Rintsch
 
L

Lawrence D'Oliveiro

Bryan Olson said:
The keyword "lambda" sucks. ...

Alonzo Church's calculus used the *symbol*.

The keyword was popularized by LISP, and hence adopted by most other
languages to copy the concept.

In my view, it's no worse than using "=" for assignment instead of equality.
"function" would be a much better keyword.

As used that way in JavaScript.
 
L

Lawrence D'Oliveiro

Cristian said:
I think it would make more sense to have beginners _know_ that functions
are like all other variables ...

Functions are not variables. Though they are values, and can be held in
variables.

In Python, every name is a variable, and can be assigned to.
 
L

Lawrence D'Oliveiro

In message <[email protected]>,
A question: if you WERE to implement function definitions as normal
expressions, how would you go about embedding it within an expression?

x = map(def a:
<line of code>
<line of code>
<line of code>
, [1, 2, 3])

Perl can do it just fine:

$x = map
(
sub
{
...
},
[1, 2, 3]
);

The fact that Python has difficulties is purely a demonstration of the
limitations of indentation-controlled syntax, not a criticism of the
concept itself.
 
P

Paul Rubin

Lawrence D'Oliveiro said:
The fact that Python has difficulties is purely a demonstration of the
limitations of indentation-controlled syntax, not a criticism of the
concept itself.

Not even. Haskell has indentation syntax (they call it "layout")
but can have multi-line function definitions inside expressions.
 
B

Bruno Desthuilliers

Cristian a écrit :
For consistency I would suggest this, but Python already does this!

Foo = type('Foo', (object, ), {'bar': lambda self, bar: bar})

I've created a new class and then binded it to name afterwards. If you
can import modules without special syntax and you can create classes
without special syntax, why should functions be treated any
differently?

You already can create functions without using the def statement:

Help on class function in module __builtin__:

class function(object)
| function(code, globals[, name[, argdefs[, closure]]])
|
| Create a function object from a code object and a dictionary.
| The optional name string overrides the name from the code object.
| The optional argdefs tuple specifies the default argument values.
| The optional closure tuple supplies the bindings for free variables.
|


HTH
 
M

Marc 'BlackJack' Rintsch

You already can create functions without using the def statement:

Help on class function in module __builtin__:

class function(object)
| function(code, globals[, name[, argdefs[, closure]]])
|
| Create a function object from a code object and a dictionary.
| The optional name string overrides the name from the code object.
| The optional argdefs tuple specifies the default argument values.
| The optional closure tuple supplies the bindings for free variables.
|

Where the heck does *this* come from? Neither Python 2.5.1 nor the
3.0alpha has this in `__builtin__`.

Ciao,
Marc 'BlackJack' Rintsch
 

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,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top