Although his learning experience has gone mostly smoothly, he's hit a
lot of speed bumps with functions. Specifically, he's having trouble
thinking of functions as first order data (don't worry, I haven't
confused him with such terminology yet). He had a little trouble
understanding that you can pass functions as arguments to other
functions (e.g., passing a key to the list.sort method). He also had a
little trouble grasping functions within other functions. Last but not
least, he had trouble grasping methods in class declarations,
especially the required self as the first argument (I'm sure he wasn't
the first).
Now, my friend's a smart guy so I know it isn't any lack of brain
cells on his part. I still remember many students in my CS classes
having trouble grasping the very same concept. 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. I began to wonder if there was anything Python could do to
help newcomers grasp the power of first order functions or, as
Pythonistas put it, everything is an object.
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. So, when
a new programmer is first introduced to functions they are immediately
confronted with the notion that functions are "different". After all,
they have their own special syntax. This seems to only further the
separation newbies make between "data" and "functions" or "stuff" and
"actions". Now, the vast majority of us learned this dichotomy when we
first began to program, so we are ingrained to assume and even expect
a different syntax for function declaration, but in a program like
Python there doesn't seem to be any other reason to have it.
Furthermore, I think it actually inhibits the learning of the
uninitiated. We can, of course, keep the current syntax as sugar.
To someone who's learning to program wouldn't a syntax like the
further give them all they need and also reinforces the idea that
functions are data just like everything else?
my_function = function(foo, bar): pass
an_instance_method = function(self, foo): pass
a_method_declaration = method(self, foo): pass
The last one is mostly my pet peeve of having Python "magically"
create methods out of (what is essentially) a function declaration.
When I first learned it, it felt wrong but you had to press through it
because there was really no other way of declaring methods.
What do you think? Have you hit this roadblock when helping others
learn Python? Does the current syntax make you feel that functions are
still treated as second class (get it?) citizens?
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
As for the method stuff, check out staticmethod(). If you assign
staticmethod(<function here>) to an object, it will be treated as a
normal function and not as a "method."
I have my own personal opinions about how methods should be in Python,
but, whatever. It's weird to deal with stuff like this:
x.y = re.match # Assign a function to an attribute of a class, but it
doesn't work because you can't assign anything but methods!
x.y = staticmethod(re.match) # Ugly
True, there is lambda, but that is very limited. It might be useful
for key arguments, but not much else. It doesn't solve the teaching
problem of "See, functions are just like any other data type. You can
assign it to a variable." 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. 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.
Again, it's not necessary as much as it's more intuitive and obvious
what's going on. This helps a beginner sort out the process from the
syntax without taking it on faith. They can see the class declaration
and see "I'm defining just another attribute to this class only this
time it happens to be method".
There is nothing functionally lacking in Python. I'm just curious if
there's anything Python can do syntax-wise to help a person better
grasp programming ideas and Python's inner workings.
Guido apparently doesn't like lambda; I'm not really sure why, it's
extremely useful. There were rumors of it leaving in Python 3000, but
thankfully there was the decision to keep them. (I have a feeling if
they weren't kept in, a project fork would have happened or such.)
Anyway, one of the biggest problems implementation wise is indentation
in an expression - there is no expression currently that uses
significant whitespace. Python draws a pretty clear line between
expression and statement. I do agree with you however, it seems as if
there is an arbitrary line between function definitions and normal
variable assignment that shouldn't be there for the sake of
consistency.
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])
It looks hideous in my opinion and lining up the , with the def is
ugly. Not to mention currently, inside groupings, whitespace is
ignored. How would you handle a whitespace signif. expression inside a
grouping which by definition ignores whitespace?
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. I
would follow Javascript and call it "function." Also, I think
parentheses should be required.
If there's no implementation problem, I don't see why Python shouldn't
allow the above example, but I would certainly discourage it. Just
like Python doesn't prevent you from writing an insanely long and
convoluted function, Python shouldn't enforce any arbitrary length in
anonymous functions. I think the above example should be discouraged
as a style violation, not syntax.
Cristian wrote:
> 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. 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.
I think key may be to discuss names and name binding with your friend. How
a name is not the object it self, like a variable is in other languages.
For example show him how an object can have more than one name. And discus
how names can be bound to nearly anything, including classes and functions.
> Again, it's not necessary as much as it's more intuitive and obvious
> what's going on. This helps a beginner sort out the process from the
> syntax without taking it on faith. They can see the class declaration
> and see "I'm defining just another attribute to this class only this
> time it happens to be method".
>
> There is nothing functionally lacking in Python. I'm just curious if
> there's anything Python can do syntax-wise to help a person better
> grasp programming ideas and Python's inner workings.
You could also discus factory functions with him. Once he gets that a
function can return another function, then it won't be so much of a leap
for a function to take a function as an argument.
Of course he'll figure out all this sooner or later anyway. You can't be
an engineer without a fair amount of brain cells committed to processing
abstract concepts.
Cheers,
Ron
Cristian wrote:
> 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. 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.
I think key may be to discuss names and name binding with your friend. How
a name is not the object it self, like a variable is in other languages.
For example show him how an object can have more than one name. And discus
how names can be bound to nearly anything, including classes and functions.
> Again, it's not necessary as much as it's more intuitive and obvious
> what's going on. This helps a beginner sort out the process from the
> syntax without taking it on faith. They can see the class declaration
> and see "I'm defining just another attribute to this class only this
> time it happens to be method".
>
> There is nothing functionally lacking in Python. I'm just curious if
> there's anything Python can do syntax-wise to help a person better
> grasp programming ideas and Python's inner workings.
You could also discus factory functions with him. Once he gets that a
> I think key may be to discuss names and name binding with your friend. How
> a name is not the object it self, like a variable is in other languages.
> For example show him how an object can have more than one name. And discus
> how names can be bound to nearly anything, including classes and functions.
I could discuss name binding but it would be great if Python said this
itself. After all, you can even bind a module with the foo = bar
syntax by using __import__ function. If function definitions followed
the same pattern, I think a beginner would subconsciously (maybe even
consciously) realize that function names are just like everything
else. Actually, this would be helpful for many people. If you come
from a language like Java you're used to thinking of attributes and
methods as living in different namespaces. I think a new syntax will
encourage seasoned programmers think in a more Pythonic way.
Python has done a very good job in easing people into programming. My
friend doesn't come to me very often because the syntax is clear and
simple and the builtin datatypes allow you to do so much. My goal is
that I would never have to explain to him about name binding; that
he'd pick it up by learning the language on his own. He's learned
lists, dictionaries and even some OOP without me. I don't think name
binding would be a stretch.
> You could also discus factory functions with him. Once he gets that a
> function can return another function, then it won't be so much of a leap
> for a function to take a function as an argument.
I think this isn't the most intuitive way of approaching first order
functions. It's true that if a function can return another function
then a function must be first order (i.e., it's just like any other
variable), but that seems almost backwards to me. I think it would
make more sense to have beginners _know_ that functions are like all
other variables and can therefore be passed by other functions or
returned by other functions. That I think would be better accomplished
if they define functions the same way you would define other variables
that you know can be passed and returned.
> To someone who's learning to program wouldn't a syntax like the
> further give them all they need and also reinforces the idea that
> functions are data just like everything else?
>
> my_function = function(foo, bar): pass
> an_instance_method = function(self, foo): pass
> a_method_declaration = method(self, foo): pass
I think one followup has already alluded to the division
between Python `statements' and `expressions'. The `def'
statement may create and bind a value, but since it's a
statement and not an expression, it doesn't have any value.
Python is not a functional programming language. It probably
could be reinvented to eliminate statements, but ... there
are already plenty of languages to choose from.
If we're going there, though, I think it's obvious that
once you have defined
an_instance_method = function(self, foo): ...
it should be invoked
an_instance_method(an_instance, foo)
which would be much less messy in nested expressions where
the current standard OOP notation flips from right to left
too much ...
string.join(x.split('-'), '').lower()
--> lower(string.join('', split(x, '-')))
It might make for some interesting problems, but that's what
it's about, changing things so it stays fun for everyone.
At the same time, partial function parameter binding should
be implemented, so you could say
dotted = string.join('.')
...
v = dotted(['comp', 'lang', 'python'])
As you probably well know, that isn't my idea, it's a common
functional programming language idiom.
Donn Cave, do...@u.washington.edu
However, you still have to solve the problem of using a single-line
construct (x = y) with a multi-line definition. That is the essential
difference that def is designed to solve. The __import__ trick works
because import is also a single line construct.
The only proposal given in this thread is using consistent indentation
within the parentheses, but parentheses are already explicitly designed
to let you ignore the whitespace rules. To suddenly create a situation
in which you have significant whitespace on the right side of an
assignment statement, and *within parentheses* will break too much code,
and make the solution unnecessarily ugly. Multi-line lambdas have been
rejected because of this very problem, so unless you have a clean
solution, I think your proposal falls into the category of "would be
nice, but not in Python."
Cheers,
Cliff
If your friend understands variables and functions and he can't make
the "leap" (and assuming you're right, of course) then your friend
doesn't understand variables and functions.
Happy Friday.
Sean
> --
> http://mail.python.org/mailman/listinfo/python-list
>
--
Sean Tierney
--
Sean Tierney
http://www.artima.com/weblogs/viewpost.jsp?thread=147358
You, Guido, and I all agree that anonymous functions in expressions
are ugly. There's no argument there. I wouldn't expect any self
respecting programmer to do such a thing even if it was available to
them (in Python that is).
I suppose my question is, taking into account the potential of ugly
code that could be created, and the fact that it's technically
feasible, would it still be worth adding anonymous functions to
explicitly show the first order nature of functions and show that
functions are in the same namespace as all other variables?
I suppose a solution could be to allow the my_function = function(foo,
bar): ... syntax but throw a syntax error if the function isn't being
bound to a variable, but that would cause other problems. From that
syntax you would assume that it's possible to create an anonymous
function wherever a variable is expected. That's not very intuitive
either.
I could """Just tell him that "functions are like all other variables
and can
therefore be passed by other functions or returned by other functions.
" """ but wouldn't it be great if Python did this for me? It seems to
me that the ability for Python to explicitly state that functions-are-
like-other-variables is there so why not expose it?
> If your friend understands variables and functions and he can't make
> the "leap" (and assuming you're right, of course) then your friend
> doesn't understand variables and functions.
To say that you understand variables and functions is language
specific. You can't translate your knowledge of variables and
functions from Python to Java and vice-versa. They are treated
completely different. Perhaps you can translate your Python
understanding of functions and variables to Javascript but not to C.
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. For
straightforward tasks, like sorting lists with a custom ordering,
functional progamming merely a convenience, and can be done without.
So I'm -1 on syntactic changes to the language to support a pedagogical
use that's not crucially important.
Now, as for the more general question--How do you teach functional
concepts?--because some people do need to know it. I suspect it's one of
those things where there are two possibilities and not much in between.
Either
1. The person gets it right away.
or
2. The person doesn't get it right away.
In the latter case, trying to teach it conceptually is probably
hopeless. Best thing to do is teach functional usage for certain use
cases. For instance, teach someone to define a function returning a key,
and have them use "key=myfunc" in list.sort--and not worry about why it
works. If they keep at it, eventually one of two things will happen.
Either,
2a. The person will have an "A ha! I get it now!" moment, and will
finally understand the concept.
or
2b. The person will never get it.
Carl Banks
Cristian wrote:
> On Sep 21, 3:44 pm, Ron Adam <r...@ronadam.com> wrote:
>
>> I think key may be to discuss names and name binding with your friend. How
>> a name is not the object it self, like a variable is in other languages.
>> For example show him how an object can have more than one name. And discus
>> how names can be bound to nearly anything, including classes and functions.
>
> I could discuss name binding but it would be great if Python said this
> itself. After all, you can even bind a module with the foo = bar
> syntax by using __import__ function. If function definitions followed
> the same pattern, I think a beginner would subconsciously (maybe even
> consciously) realize that function names are just like everything
> else. Actually, this would be helpful for many people. If you come
> from a language like Java you're used to thinking of attributes and
> methods as living in different namespaces. I think a new syntax will
> encourage seasoned programmers think in a more Pythonic way.
I could see methods having their own keywords. Then functions defined in
classes would be static methods without any extra work. But to do that
would break a lot of already existing code as well as confuse a lot of
current users.
> Python has done a very good job in easing people into programming. My
> friend doesn't come to me very often because the syntax is clear and
> simple and the builtin datatypes allow you to do so much. My goal is
> that I would never have to explain to him about name binding; that
> he'd pick it up by learning the language on his own. He's learned
> lists, dictionaries and even some OOP without me. I don't think name
> binding would be a stretch.
Chances are he'll run into a gotcha where an object has two names and sort
it out that way. Which is why I suggested starting there. It will save
him some grief if he hasn't run into it yet.
>> You could also discus factory functions with him. Once he gets that a
>> function can return another function, then it won't be so much of a leap
>> for a function to take a function as an argument.
>
> I think this isn't the most intuitive way of approaching first order
> functions.
The Python tutorial does this by defining a function, then assigning it to
another name and calling it from the new name.
http://www.python.org/doc/current/tut/tut.html
> It's true that if a function can return another function
> then a function must be first order (i.e., it's just like any other
> variable), but that seems almost backwards to me. I think it would
> make more sense to have beginners _know_ that functions are like all
> other variables and can therefore be passed by other functions or
> returned by other functions. That I think would be better accomplished
> if they define functions the same way you would define other variables
> that you know can be passed and returned.
I think it gets awkward fairly quick if you try and work out how to do
this. There have been requests in the past to have functions assigned to
names like other things.
The nice thing about the current syntax is it more closely resembles what
you would type at call time, so it is more self documenting.
def sum(x, y):
return x + Y
total = sum(1, 2)
I think changing that would be trading one type of clarity for another.
Ron
> 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?
>>> def parrot(colour='red'):
... return "I'm a parrot with %s plumage." % colour
...
>>> bird = parrot # note the lack of brackets
>>> type(bird)
<type 'function'>
>>> bird('green')
"I'm a parrot with green plumage."
Or using lambda:
>>> parrot = lambda colour: "I'm a parrot with %s plumage." % colour
>>> parrot("purple")
"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?
--
Steven.
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.
> 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
> 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
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.
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
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?
> On 22 Sep., 08:56, Paul Rubin <http://phr...@NOSPAM.invalid> wrote:
>> Kay Schluehr <kay.schlu...@gmx.net> writes:
>> > 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.
>
> 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.
Ciao,
Marc 'BlackJack' Rintsch
From the link:
"Abstract
As software..."
That's it, lost me already. You ever see the kinds of programs
mechanical engineers write? It isn't software.
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.
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.
> 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
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
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.
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
Scott....@Acm.Org
> On Sep 22, 1:15 pm, Marc 'BlackJack' Rintsch <bj_...@gmx.net> wrote:
>> On Sat, 22 Sep 2007 02:44:35 -0700, Kay Schluehr wrote:
>> > 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.
>
> 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
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]
--
--Bryan
[...]
> 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-
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.
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
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.
--
--Bryan
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.
> 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.
--
Erik Max Francis && m...@alcyone.com && http://www.alcyone.com/max/
San Jose, CA, USA && 37 20 N 121 53 W && AIM, Y!M erikmaxfrancis
No man quite believes in any other man.
-- H.L. Mencken
>> 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 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.
>>> f = lambda: 3
>>> f.__name__
'<lambda>'
It's just that all functions created by lambda share the same name.
If you really want an anonymous function...
>>> def foo():
... return 3
...
>>> foo.__name__ = ''
>>> foo
<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).
--
Steven.
> 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?
Scott David Daniels wrote:
> Ron Adam wrote:
>>
>> Scott David Daniels wrote:
>>> Cristian wrote:
>>>> On Sep 21, 3:44 pm, Ron Adam <r...@ronadam.com> wrote:
>>>>
>>>>> I think key may be to discuss names and name binding with your friend.
>>> Here's an idea:
>>>
>>> import math
>>>
>>> def sin_integral(start, finish, dx): ...
>>> def cos_integral(start, finish, 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):...
>> 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.
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
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
It's actually a mostly *un*common syntax when it comes to functions. The
only "mainstream" language I know allowing such a syntax is javascript.
Now given python's parsing rules, I wonder how this could be implemented...
> Python has the def foo(): syntax. So, when
> a new programmer is first introduced to functions they are immediately
> confronted with the notion that functions are "different".
Which is the case in most non functional languages.
> After all,
> they have their own special syntax. This seems to only further the
> separation newbies make between "data" and "functions" or "stuff" and
> "actions". Now, the vast majority of us learned this dichotomy when we
> first began to program, so we are ingrained to assume and even expect
> a different syntax for function declaration, but in a program like
> Python there doesn't seem to be any other reason to have it.
Technically, I'd say "patsing rules". From a more conceptual POV, Python
was meant to be the missing link between shell scripts and C - and some
design choices clearly (IMHO) came from the desire to look familiar
enough to C programmers. Even if Python ended up with some (restricted)
support for functional programming, it's still has it's roots in
procedural programming.
> Furthermore, I think it actually inhibits the learning of the
> uninitiated. We can, of course, keep the current syntax as sugar.
>
> To someone who's learning to program wouldn't a syntax like the
> further give them all they need and also reinforces the idea that
> functions are data just like everything else?
Python's functions are *objects* like anything else. And objects are
more than data. My 2 cents: show your friend that Python's functions are
objects, and that other objects can be callable too...
> my_function = function(foo, bar): pass
> an_instance_method = function(self, foo): pass
> a_method_declaration = method(self, foo): pass
>
> The last one is mostly my pet peeve of having Python "magically"
> create methods out of (what is essentially) a function declaration.
There's not much magic in this. What's stored as an attribute of the
class *is* a function. It's only wrapped in a method object when looked
up. And FWIW, it's the function object itself that takes care of this,
thanks to the descriptor protocol (all relevant doc is on python.org).
> When I first learned it, it felt wrong but you had to press through it
> because there was really no other way of declaring methods.
Truth is that you do *not* "declare" methods in Python.
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()
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
?-)
Scott David Daniels wrote:
> Ron Adam wrote:
>> Scott David Daniels wrote:
>>> Ron Adam wrote:
>>>> .... How about this?
>>>> def integrate(fn, x1, x2, n=100):...
>>> The point was a pedagogic suggestion, ...
>> 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, 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
Scott David Daniels wrote:
> Ron Adam wrote:
>> Scott David Daniels wrote:
>>> Ron Adam wrote:
>>>> .... How about this?
>>>> def integrate(fn, x1, x2, n=100):...
>>> The point was a pedagogic suggestion, ...
>> 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, 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. ;-)
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?
> 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?
> On 22 Sep., 02:14, Bruno Desthuilliers
> <bdesth.quelquech...@free.quelquepart.fr> wrote:
>> Kay Schluehr a crit :
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
> 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.
> 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.
> 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.
Not even. Haskell has indentation syntax (they call it "layout")
but can have multi-line function definitions inside expressions.
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
> 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
It comes from the 'new' module:
>>> import new
>>> help(new.function)
Help on class function in module __builtin__:
...
Oddly enough, the help misrepresents which module the function is coming
from.
--
Carsten Haese
http://informixdb.sourceforge.net
> 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.
[...]
> Ciao,
> Marc 'BlackJack' Rintsch
O.K. Marc, I'm convinced by the examples you presented. So init is
also special in Io and is called at the clone event to fill object
slots with data.
Now I have to track back in the discussion thread to remember why we
started to talk about Io...
>> Where the heck does *this* come from? Neither Python 2.5.1 nor the
>> 3.0alpha has this in `__builtin__`.
>
> It comes from the 'new' module:
>
>>>> import new
>>>> help(new.function)
> Help on class function in module __builtin__:
> ...
>
> Oddly enough, the help misrepresents which module the function is
> coming from.
Not exactly:
>>> help(type(lambda x: x))
Help on class function in module __builtin__:
The function type is builtin, but it doesn't have an exposed name.
`new.function` is simply a name bound to the function type.
Note the help says *class* function ...
Tim Delaney
> It comes from the 'new' module:
>
>>>> import new
>>>> help(new.function)
> Help on class function in module __builtin__:
> ...
>
> Oddly enough, the help misrepresents which module the function is coming
> from.
No, I don't think it is misrepresenting anything. The 'new' module simply
exposes names for some things which don't otherwise have names, none of
the types accessible through that module are actually defined there.
The class 'function' is a builtin definition, but by default it isn't bound
to any name accessible to the Python interpreter. If you do:
>>> def f(): pass
>>> type(f).__module__
'__builtin__'
>>> help(type(f))
Help on class function in module __builtin__:
... etc ...
then the help makes a bit more sense.
Which makes a great difference in practice !-)
Nope. They know *one* of their names - the one they've been given when
first instanciated. Which may or not be the name used to get at them...
That's exactly the point - a function may be given many names through
the assignment statement, just like any other data value. However, the
*first* name given to a function (the one in the def statement) is
special, as that is the name the function knows *itself* by.
While a function *can* be treated like any other piece of data once
you have a reference to one, the original statement does a lot more
than a normal assignment does:
- being within the scope of a function significantly alters name
binding and lookup
- return statements and yield statements are meaningful only within
the scope of a function
- you can attach decorators to a function definition
- you can include a docstring in a function definition
For the original poster, I suggest trying some of the other
suggestions in this thread, where you skip the def statement and
instead look at manipulating standard library functions like math.sin
and math.cos. Using a dictionary to select a function to run may be a
good trick to illustrate the usefulness of this technique (e.g.
passing in a command line argument to choose a function to call to
generate a test sequence)
>>> def toto(level):
... print "toto %s" % level
... if level == 0: print "done"
... else: toto(level-1)
...
>>> toto(3)
toto 3
toto 2
toto 1
toto 0
done
>>> tutu = toto
>>> def toto(level):
... print "YADDA YADDA"
...
>>> tutu(3)
toto 3
YADDA YADDA
>>>
> While a function *can* be treated like any other piece of data once
> you have a reference to one, the original statement does a lot more
> than a normal assignment does:
Indeed. But :
> - being within the scope of a function significantly alters name
> binding and lookup
Runtime stuff and 'locals' parameters of te function object initializer
AFAICT.
> - return statements and yield statements are meaningful only within
> the scope of a function
s/"within the scope"/"in the code object"/, I'd say... Look at the
signature of the function object's initializer, it takes a code object.
Please some guru correct me if I'm wrong, but AFAICT, you can have all
this working without the def statement itself (even if it's quite enough
of a boring work to justify the existence of the def statement).
Anyway, the OP suggestion was to turn the statement into an expression
(à la javascript), not to get rid of it.
> - you can attach decorators to a function definition
@decorators are just syntactic sugar for HOFs. If you want to apply a
decorator do a lambda, you don't need this syntax - just pass the lambda
as a param to the decorator.
> - you can include a docstring in a function definition
And you can add it afterwards too:
>>> toto.__doc__ is None
True
>>> toto.__doc__ = "yadda"
>>> toto.__doc__
'yadda'
Don't get me wrong, I'm not saying the def statement is useless. Just
that the reasons why this statement exists have very few to do with your
arguments here.