A critic of Guido's blog on Python's lambda

J

JShrager

There are *NO* semantic advantages for named vs unnamed functions in Python.

I feel that this conversation has glanced off the point. Let me try a
new approach:

There is the Pythonic way (whatever that is), and then The Lisp Way. I
don't know what the former is, but it has something to do with
indentation, and the (meaningless to me*) phrase "It fits your mind."
The Lisp way is quite specific: Pure Compositionality. Compositionality
encompasses and defines all aspects of Lisp, from the parens to
functional style to fundamental recursion to lambda, and even the
language itself is classically composed from the bottom up, and
compositionality enables us to create new complete languages nearly
trivially.

How this concept plays into the current conversation is not subtle:
LAMBDA forms server to directly modify the forms in which they appear.
SORT is the example that comes to mind for me. If one says: (sort ...
#'(lambda (a b) ...)) [I realize that the #' is optional, I use it here
for emphasis that there is a function being formed.] the lambda form
composes, with sort, a new type of sort -- a sort of type <whatever the
lambda function does>. Thus, the semantics of this form are localized
to the sort expression, and do not leave it -- they are, indeed,
conceptually a part of the sort expression, and to require it/them to
be moved outside and given a name breaks the conceptual
compositionality -- that is, the compositional locality of the form.

Similarly, parens and the functional fact that every form returns a
value provide compositional locality and, perhaps more importantly in
practice, compositional *mobility* -- so that, pretty much anywhere in
Lisp where you need an argument, you can pick up a form and drop it in.
[Macros often break this principle, I'll get to those in a moment.]
This is something that no other language (except some dead ones, like
APL) were able to do, and these provide incredible conceptual
flexibility -- again, I'll use the term "mobility" -- one can, in most
cases, literally move code as though it were a closed concept to
anywhere that that concept is needed.

Macros, as I have said, bear a complex relationship to this concept of
composition mobility and flexibility. The iteration macro, demonstrated
elsewhere in this thread, is an excellent example. But macros are more
subtly related to compositionality, and to the present specific
question, because, as you yourself said: All you need to do is make up
a name that isn't used....But how is one to find a name that isn't used
if one has macros? [Actually, in Lisp, even if we didn't have lambda we
could do this by code walking, but I'll leave that aside, because
Python can't do that, nor can it do macros.]

I do not hesitate to predict that Python will someday sooner than later
recognize the value of compositional flexibility and mobility, and that
it will struggle against parentheses and lambdas, but that in the end
it will become Lisp again. They all do, or die.

===

[*] BA - Biographical Annotation: Yeah, I've programmed all those
things too for years and years and years. I also have a PhD in
cognitive psychology from CMU, where I worked on how people learn
complex skills, and specifically programming. When I say that "fits
your brain" is meaningless to me, I mean that in a technical sense:
If it had any meaning, I, of all people, would know what it means;
meaning that I know that it doesn't mean anything at all.
 
A

Aaron Denney

["Followup-To:" header set to comp.lang.functional.]
- it fits most programmers brains i.e. it is similar enough to
languages that most programmers have experience with and the
differences are usually perceived to beneficial (exception:
people from a Java/C/C++ background often perceive dynamic
typing as a misfeature and have to struggle with it)

It is a misfeature. It's just less of a misfeature than the typing of
Java/C/C++, etc.
 
D

Dennis Lee Bieber

I do not hesitate to predict that Python will someday sooner than later
recognize the value of compositional flexibility and mobility, and that
it will struggle against parentheses and lambdas, but that in the end
it will become Lisp again. They all do, or die.
In 20 years... Python will be indistinguishable from FORTRAN, and
miles away from LISP <G>
--
Wulfraed Dennis Lee Bieber KD6MOG
(e-mail address removed) (e-mail address removed)
HTTP://wlfraed.home.netcom.com/
(Bestiaria Support Staff: (e-mail address removed))
HTTP://www.bestiaria.com/
 
C

Chris Lambacher

[1] I'm considering introducing bugs or misdesigns that have to be
fixed
as part of training for the purposes of this discussion. Also the

Actually, doing it _deliberately_ (on "training projects" for new people
just coming onboard) might be a good training technique; what you learn
by finding and fixing bugs nicely complements what you learn by studying
"good" example code. I do not know of this technique being widely used
in real-life training, either by firms or universities, but I'd love to
learn about counterexamples.

When I was learning C in university my professor made us fix broken programs.
He did this specifically to teach us to understand how to read compiler
warnings/errors and also how to debug software. The advantage of this in the
tutorial setting was that the TAs knew what the error was and could assist the
people in finding bugs in a controlled environment. When I later worked with
people who did not go through this training I found many of them had no clue
how to decipher the often cryptic C/C++ compiler warnings/errors (think
Borland Turbo C or MS Visual C++, GCC is pretty good in comparison) or where
to start looking for a bug (an affliction I do not possess).

-Chris
 
K

Ken Tilton

When you consider that there was just a big flamewar on comp.lang.lisp
about the lack of standard mechanisms for both threading and sockets in
Common Lisp (with the lispers arguing that it wasn't needed) I find it
"curious" that someone can say Common Lisp scales well.

We're talking about whether the language can grow to have new
capabilities, while you are talking about libraries, and specifically
whether different implementations have the same API. They all have
sockets, just not the same API, probably because, to be honest that is
not something that belongs in a /language/ API.

But those of us who bounce from implementation to implementation see a
standard APi as saving us some conditional compilation and (effectively)
rolling our own common API out of dii implementation's socket APIs, so a
few socket gurus are working on a standard now.

And yes, they will be able to do this with Common Lisp as it stands.

Try to think a little more rigorously in these discussions, Ok?

Thx, kenny

--
Cells: http://common-lisp.net/project/cells/

"Have you ever been in a relationship?"
Attorney for Mary Winkler, confessed killer of her
minister husband, when asked if the couple had
marital problems.
 
K

Ken Tilton

Alexander said:
[trimmed groups]

yes, but do not feel bad, everyone gets confused by the /analogy/ to
spreadsheets into thinking Cells /is/ a spreadsheet. In fact, for a brief
period I swore off the analogy because it was so invariably misunderstood.
Even Graham misunderstood it.


Count me in.

<g> But looking at what it says: "Think of the slots as cells in a
spreadsheet (get it?), and you've got the right idea. ", if you follow
the analogy (and know that slot means "data member" in other OO models)
you also know that Serge's Spreadsheet example would have scored a big
fat zero on the Miller Analogy Test. Serge in no way made slots in
Python classes behave like cells in a spreadsheet. He simply started
work on a Spreadsheet application, using Python classes along the way. Bzzt.

While everyone makes the mistake, it is only because few of us (me
included) read very carefully. Especially if they are more interested in
flaming than learning what someone is saying.

C'mon, people. I linked to Adobe's betting the ranch on such an idea. I
linked to Guy Steele's paper on the same idea. In which he marvelled
that it had not caught on. I could also link you to COSI over at STSCI,
presented at a Lisp Users Group Meeting in 1999 where they were jumping
up and down about the same thing. One of my users gets Cells because he
loved the KR system in Garnet. Look it up. I have more citations of
prior art. And, again, it has gone mainstream: Adobe has adopted the
paradigm.

Y'all might want to ease up on the pissing contest and learn something.
or not, I have been on Usenet before. :)

Very roughly speaking, that is supposed to be the code, not the output. So you
would start with (just guessing at the Python, it has been years since I did
half a port to Python):


v1 = one
a = determined_by(negate(sin(pi/2)+v1)
b = determined_by(negate(a)*10)
print(a) -> -2.0 ;; this and the next are easy
print(b) -> 20
v1 = two ;; fun part starts here
print(b) -> 40 ;; of course a got updated, too


do you mean 30?

I've translated my interpretation of the above to this actual python code:

from math import sin, pi
v1 = cell(lambda: 1)
a = cell(lambda:-(sin(pi/2)+v1.val), dependsOn=[v1])
b = cell(lambda: -a.val*10, dependsOn=[a],
onChange=lambda *args: printChangeBlurp(name='b',*args))
print 'v1 is', v1
print 'a is', a # -2.0 ;; this and the next are easy
print 'b is', b # 20
v1.val = 2 # ;; fun part starts here
print 'v1 now is', v1
print 'b now is', b # 30 ;; of course a got updated, too


I get the following printout:

v1 is 1
a is -2.0
b is [cell 'b' changed from <__main__.unbound object at 0xb4e2472c> to 20.0,
it was not bound]20.0
[cell 'b' changed from 20.0 to 30.0, it was bound ] v1 now is 2
b now is 30.0

Does that seem vaguely right?

<g> You have a good start. But you really have to lose the manual wiring
of dependencies, for several reasons;

-- it is a nuisance to do
-- it will be a source of bugs
-- it will be kind of impossible to do, because (in case you missed
it), the rule should be able to call any function and establish a
dependency on any other cell accessed. So when coding a change to a
function, one would have to go track down any existing rule to change
its dependsOn declaration. never mind the pain in th first place of
examining the entire call tree to see what else gets acessed.
-- it gets worse. I want you to further improve your solution by
handling rules such as this (I will just write Lisp):

(if (> a b)
c ;; this would be the "then" form
d)) ;; this is the 'else'

The problem here is that the rule always creates dependencies on a and
b, but only one of c and d. So you cannot write a dependsOn anyway
(never mind all the other reasons for that being unacceptable).
Is the above what you want (you can also dynamically assign onChange later
on, as required or have a list of procedures instead)?

Your onChange seems to be working fine. One thing we are glossing over
here is that we want to use this to extend the object system. In that
case, as I said and as no one bothered to comprehend, we want /slots/ to
behave like spreadsheet cells. Not globals. And I have found that these
onChane deals are most sensibly defined on slots, not cell by cell.

That said, if you did work something up similar for Python classes, i
have no doubt you could do that.

Again, if anyone is reading and not looking to just have a flamewar,
they will recall i have already done once a partial port of Cells to
python. (I should go look for that, eh? It might be two computer systems
back in the closet though. said:
Updating on write rather than recalculating on read does in itself not seem
particularly complicated.

<heh-heh> Well, there are some issues. B and C depend on A. B also
depends on C. When A changes, you have to compute C before you compute
B, or B will get computed with an obsolete value of C and be garbage.
And you may not know when A changes that there is a problem, because as
you can see from my example (let me change it to be relevant):

(if (> a d) c e)

It may be that during the prior computation a was less= d and did /not/
depend on c, but with the new value of a is > d and a new code branch
will be taken leading to c.

It was not that hard to figure all that out (and it will be easier for
you given the test case <g>) but I would not say propagation is
straightforward. There are other issues as well, including handling
assignments to cells within observers. This is actually useful
sometimes, so the problem needs solving.
OK, so in what way does the quick 35 line hack below also completely miss your
point?

What is that trash talking? I have not seen your code before, so of
course I have never characterized it as completely missing the point.
Spare me the bullshit, OK?

Alexander, you are off to a, well, OK start on your own PyCells. You
have not made a complete mess of the low-hanging fruit, but neither have
you done a very good job. Requiring the user to declare dependencies was
weak -- I never considered anything that (dare I say it?) unscaleable.
Like GvR with Python, I knew from day one that Cells had to very simple
on the user. Even me, their developer. But do not feel too bad, the GoF
Patterns book described more prior art (I might have mentioned) and they
had explicit (and vague) subscribe/unsubscribe requirements.

As for the rest of your code, well, propagation should stop if a cell
recomputes the same value (it happens). And once you have automatic
dependency detection, well, if the rule is (max a b) and it turns out
that b is just 42 (you had cell(lambda 1)... why not just cell(1) or
just 1), then do not record a dependency on b. (Another reason why the
user cannot code dependsOn -- it is determined at run time, not by
examination of the code.

Now we need to talk about filters on a dependency....

kenny (expecting more pissing and less reading of the extensive on-line
literature on constraints)


--
Cells: http://common-lisp.net/project/cells/

"Have you ever been in a relationship?"
Attorney for Mary Winkler, confessed killer of her
minister husband, when asked if the couple had
marital problems.
 
T

Tomasz Zielonka

I said:
Monads are one of those parts of functional programming I've never really
got my head around, but as I understand them, they're a way of
transforming what looks like a sequence of imperative programming
statements that operate on a global state into a sequence of function
calls that pass the state between them.

This is a description of only one particular kind of monad - a state
monad. A generalisation of your statement would be something like this:
"they're a way of writing what looks like a sequence of imperative
programming statements that, depending on the monad, can have certain
computational side-effects (like operating on a global state) in a
purely functional way". But this doesn't explain much. If you want to
know more, there are some pretty good tutorials on
http://www.haskell.org/.
So, what would be a statement in an imperative language is an anonymous
function that gets added to the monad, and then, when the monad is run,
these functions get executed.

A monad is a type, it isn't run. The thing you run can be called a
monadic action. You don't add functions to a monad (in this sense), you
build a monadic action from smaller monadic actions, gluing them with
functions - here's where anonymous functions are natural.
The point being, that you have a lot of small functions (one for each
statement) which are likely not to be used anywhere else, so defining
them as named functions would be a bit of a pain in the arse.
Exactly!

Actually, defining them as unnamed functions via lambdas would be annoying
too, although not as annoying as using named functions - what you really
want is macros, so that what looks like a statement can be interpreted is
a piece of code to be executed later.

Haskell has one such "macro" - this is the do-notation syntax. But it's
translation to ordinary lambdas is very straightforward, and the choice
between using the do-notation or lambdas with >>= is a matter of
style.

Best regards
Tomasz
 
A

Alex Martelli

Frank Buss said:
&key is something like keyword arguments in Python. And looks like you are

Ah, thanks.
right again (I've tested it in Pyhton) and my assumption was wrong, so the
important thing is to support closures, which Python does, even with local
function definitions.

We do appear to entirely agree. In Python <= 2.4, where if is just a
statement (not an expression), you'd need some trick to get this effect
with a lambda, e.g.:

def black_white(function, limit, key=None):
return lambda x,y: 1.0 * (function(x,y) > limit)

assuming it's important to get a float result -- the > operator per se
returns an int, so you can call float() on it, or multiply it by 1.0,
etc -- if you had two arbitrary colors, e.g.

def two_tone(function, limit, key=None, low=0.0, high=1.0):
return lambda x,y: (low, high)[function(x,y) > limit]

which is a pretty obscure alternative. In Python >= 2.5, an if
expression has been added, but I'll leave you to judge if it's actually
an improvement (sigh)...:

def two_tone(function, limit, key=None, low=0.0, high=1.0):
return lambda x,y: high if function(x,y) > limit else low

Personally, I'd rather use the named-function version. Anyway, they're
all semantically equivalent (sigh), and the key point is that the
semantics (building and returning functions on the fly) IS there,
whether the functions are named or unnamed, as we agree.


Alex
 
A

Alex Martelli

Chris Lambacher said:
[1] I'm considering introducing bugs or misdesigns that have to be
fixed
as part of training for the purposes of this discussion. Also the

Actually, doing it _deliberately_ (on "training projects" for new people
just coming onboard) might be a good training technique; what you learn
by finding and fixing bugs nicely complements what you learn by studying
"good" example code. I do not know of this technique being widely used
in real-life training, either by firms or universities, but I'd love to
learn about counterexamples.

When I was learning C in university my professor made us fix broken programs.
He did this specifically to teach us to understand how to read compiler
warnings/errors and also how to debug software. The advantage of this in the
tutorial setting was that the TAs knew what the error was and could assist the
people in finding bugs in a controlled environment. When I later worked with
people who did not go through this training I found many of them had no clue
how to decipher the often cryptic C/C++ compiler warnings/errors (think
Borland Turbo C or MS Visual C++, GCC is pretty good in comparison) or where
to start looking for a bug (an affliction I do not possess).

Great to hear that SOME teachers use this technique. I think it would
be about just as valuable with any language (or other similar piece of
technology).


Alex
 
T

Tomasz Zielonka

Alex said:
Worst case, you name all your functions Beverly so you don't have to
think about the naming

I didn't think about this, probably because I am accustomed to Haskell,
where you rather give functions different names (at the module top-level
you have no other choice). I just checked that it would work for nested
Beverly-lambdas (but could be quite confusing), but how about using more
then one lambda in an expression? You would have to name them
differently.
but you also have a chance to use meaningful names (such as,
presumably, zipperize_widget is supposed to be here) to help the
reader.

[OK, I am aware that you are talking solely about lambdas in Python,
but I want to talk about lambdas in general.]

Sometimes body of the function is its best description and naming what
it does would be only a burden. Consider that the same things that you
place in a loop body in python, you pass as a function to a HOF in
Haskell. Would you propose that all loops in Python have the form:

def do_something_with_x(x):
...
do something with x
for x in generator:
do_something_with_x(x)

Also, having anonymous functions doesn't take your common sense away, so
you still "have a chance".

Best regards
Tomasz
 
A

Alex Martelli

Tomasz Zielonka said:
Also, having anonymous functions doesn't take your common sense away, so
you still "have a chance".

I've seen many people (presumably coming from Lisp or Scheme) code
Python such as:

myname = lambda ...

rather than the obvious Python way to do it:

def myname(...

((they generally do that right before they start whining that their
absurd choice doesn't let them put statements inside the "unnamed
function that they need to assign to a name")).

_THAT_ is what having many semantically overlapping (or identically
equivalent) ways to perform the same task does to people: it takes the
common sense away from enough of them that I'm statistically certain to
have to wrestle with some of them (be it as suppliers, people I'm trying
to help out on mailing lists etc, students I'm mentoring -- at least
being at Google means I don't have to fear finding such people as my
colleagues, but the memories and the scars of when I was a freelance
consultant are still fresh, and my heart goes out to the 99% of sensible
Pythonistas who don't share my good luck).

As long as Guido planned to remove lambda altogether in Python 3.0, I
could console myself with the thought that this frequent, specific
idiocy wasn't one I would have to wrestle with forever; now I know I
will have no such luck -- it's back to the dark ages. ((If I ever _DO_
find a language that *DOES* mercilessly refactor in pursuit of the ideal
"only one obvious way", I may well jump ship, since my faith in Python's
adherence to this principle which I cherish so intensely has been so
badly broken by GvR's recent decisions to keep lambdas, keep [<genexp>]
as an identical synonym for list(<genexp>), add {1,2,3} as an identical
synonym for set((1,2,3))...); though, being a greedy fellow, I'll
probably wait until all my Google options have vested;-)).


Alex
 
A

Alex Martelli

....an alleged reply to me, which in fact quotes (and responds to) only
to statements by Brian, without mentioning Brian...

Mr May, it seems that you're badly confused regarding Usenet's quoting
conventions. You may want to repeat your answer addressing specifically
the poster you ARE apparently answering. Nevertheless, I'll share my
opinions:
Using lambda in an expression communicates the fact that it will
be used only in the scope of that expression. Another benefit is that
declaration at the point of use means that all necessary context is
available without having to look elsewhere. Those are two pragmatic
benefits.

You still need to look a little bit upwards to the "point of use",
almost invariably, to see what's bound to which names -- so, you DO
"have to look elsewhere", nullifying this alleged benefit -- looking at
the def statement, immediately before the "point of use", is really no
pragmatic cost when you have to go further up to get the context for all
other names used (are they arguments of this function, variables from a
lexically-containing outer function, assigned somewhere...), which is
almost always. And if you think it's an important pragmatic advantage
to limit "potential scope" drastically, nothing stops you from wrapping
functions just for that purpose around your intended scope -- me, I find
that as long as functions are always kept small (as they should be for a
host of other excellent reasons anyway), the "ambiguity" of scope being
between the def and the end of the containing function is nil (literally
nil when the statement right after the def, using the named function, is
a return, as is often the case -- pragmatically equivalent to nil when
the statements following the def are >1 but sufficiently few).

Your "pragmatic benefits", if such they were, would also apply to the
issue of "magic numbers", which was discussed in another subthread of
this unending thread; are you therefore arguing, contrary to widespread
opinion [also concurred in by an apparently-Lisp-oriented discussant],
that it's BETTER to have magic unexplained numbers appear as numeric
constants "out of nowhere" smack in the middle of expressions, rather
than get NAMED separately and then have the names be used? If you
really believe in the importance of the "pragmatic benefits" you claim,
then to be consistent you should be arguing that...:

return total_amount * 1.19

is vastly superior to the alternative which most everybody would deem
preferable,

VAT_MULTIPLIER = 1.19
return total_amount * VAT_MULTIPLIER

because the alternative with the magic number splattered inexplicably
smack in the middle of code "communicated the fact" that it's used only
within that expression, and makes all context available without having
to look "elsewhere" (just one statement up of course, but then this
would be identically so if the "one statement up" was a def, and we were
discussing named vs unnamed functions vs "magic numbers").

That's a very minimal cost relative to the benefits.

To my view of thinking, offering multiple semantically equivalent ways
(or, perhaps worse, "nearly equivalent but with subtle differences"
ones) to perform identical tasks is a *HUGE* conceptual cost: I like
languages that are and stay SMALL and SIMPLE. Having "only one obvious
way to do it" is just an ideal, but that's no reason to simply abrogate
it when it can so conveniently be reached (my only serious beef with
Python it has it *HAS* abdicated the pursuit of that perfect design
principle by recent decisions to keep lambda, and to keep the syntax
[<genexp>] as an identical equivalent to list(<genexp>), in the future
release 3.0, which was supposed to simplify and remove redundant stuff
accreted over the years: suddenly, due to those decisions, I don't
really look forward to Python 3.0 as I used to - though, as I've already
mentioned, being a greedy fellow I'll no doubt stick with Python until
all my Google options have vested).

You haven't made your case for named functions being preferable.

I think it's made at least as well as the case for using constant-names
rather than "magic numbers" numeric constants strewn throughout the
code, and THAT case is accepted by a wide consensus of people who care
about programming style and clarity, so I'm pretty happy with that.


Alex
 
A

Adam Jones

Ken said:
Alexander said:
[trimmed groups]

yes, but do not feel bad, everyone gets confused by the /analogy/ to
spreadsheets into thinking Cells /is/ a spreadsheet. In fact, for a brief
period I swore off the analogy because it was so invariably misunderstood.
Even Graham misunderstood it.


Count me in.

<g> But looking at what it says: "Think of the slots as cells in a
spreadsheet (get it?), and you've got the right idea. ", if you follow
the analogy (and know that slot means "data member" in other OO models)
you also know that Serge's Spreadsheet example would have scored a big
fat zero on the Miller Analogy Test. Serge in no way made slots in
Python classes behave like cells in a spreadsheet. He simply started
work on a Spreadsheet application, using Python classes along the way. Bzzt.

While everyone makes the mistake, it is only because few of us (me
included) read very carefully. Especially if they are more interested in
flaming than learning what someone is saying.

I don't really mean any disrespect here, but if an analogy is not
interpreted correctly by a large group of people, the analogy is crap,
not the people. Yes, I understood it, specifically because I have spent
enough time dinking around with cell functions in a spreadhseet to
understand what you meant.

Maybe it would help to change the wording to "functions with cell
references in a spreadsheet" instead of "cells in a spreadsheet". Yes,
you lose the quippy phrasing but as it is most people use spreadsheets
as "simple database with informal ad hoc schema" and mostly ignore the
more powerful features anyways, so explicit language would probably
help the analogy. I'm guessing if you made some vague allusions to how
"sum(CellRange)" works in most spreadsheets people would get a better
idea of what is going on.
 
J

JShrager

If I ever _DO_ find a language that *DOES* mercilessly refactor in pursuit
of the ideal "only one obvious way", I may well jump ship, since my faith in
Python's adherence to this principle which I cherish so intensely has
been so badly broken ...

The phrase "only one obvious way..." is nearly the most absurd
marketing bullshit I have ever heard; topped only by "it fits your
brain". Why are so many clearly intelligent and apparently
self-respecting hard-core software engineers repeating this kind of
claptrap? It sounds more like a religious cult than a programming
language community. If one of my students answered the question: "Why
use X for Y?" with "X fits your brain." or "There's only one obvious
way to do Y in X." I'd laugh out loud before failing them.
 
A

Anton Vredegoor

When you consider that there was just a big flamewar on comp.lang.lisp
about the lack of standard mechanisms for both threading and sockets in
Common Lisp (with the lispers arguing that it wasn't needed) I find it
"curious" that someone can say Common Lisp scales well.

In comp.lang.python there are often discussions about which is the best
web framework or what is the best gui. There seems to be some common
meme in these kinds of discussions and the lambda controversy. I'm even
ready to expand the concept even more and include documentation problems
and polymorphic typing.

So what is the big advantage of using parens then that is making people
give up documenting their code by naming functions? (See, I'm getting
into the right kind of lingo for discussing these kind of questions)

Well, there seems to be some advantage to conceptually decoupling a
function from what it is doing *now* (which can be easily named) and
what it is doing in some other situation. Naming things is only a
ballast and makes the mental model not "fit the brain" (introducing
pythonic terminology here for the lispers).

This is a lot like polymorphic functions. For example an adding function
sometimes adds integers and sometimes floats or complex variables and
it can be defined just once without specifying which type of parameters
it is going to get. I assume this to be a piece of cake for most lispers
and pythoneers, but possibly this could still confuse some static typers.

An anonymous function is like a polymorphic function in that it is
possible to make the "mental model" about it polymorphic, instead of
just its parameters. This enables the lispers to just "take what it does
and paste it where that needs to be done" (inventing crypto speak here).

This is a very effective way of handling operations and it would
surprise me if not 99 percent of the Python coders do things mentally
this way too and only add names and documentation at the last possible
moment (mental compile time documentation procedure).

So here we're integrating mental models concerning polymorphism into the
way we talk and think about code, and naming things explicitly always
seems to be a burden.

But now we let the other side of our brain speak for a moment, it was
always the side that translated everything we wanted to say to each
other here into mental Unicode so that we can hear what the others are
saying (further diving into the linguistic pit I am digging here).

Yes, communication is what suffers from *not* naming things, and right
after it documentation and standardization. How else are we going to
communicate our findings verbally to the non coders and the trans coders?

Also naming functions and variables can help us create appropriate
mental models that 'fix' certain things in place and keep them in the
same state, because now they are 'documented'. This promotes people
being able to work together and also it enables measuring progress, very
important aspects for old world companies who won't understand the way
things are evolving (even if they seem to have roaring success at the
moment).

Not to say that I invented something new, it was always a theme, but now
it's a meme,(he, he), the conflict between the scripture and the
mysticism. It's such a pity that everyone understands some way or
another that mysticism is the way things work but that none wants to
acknowledge it.

What am I doing here coding Python one might ask, well, the knowledge
has to be transfered to my brain first *somehow*, and until someone
finds a better way to do that or until there is so much procedural
information in my head that I can start autocoding (oh no) that seems to
be the better option.

Anton
 
T

Thomas F. Burdick

When you consider that there was just a big flamewar on comp.lang.lisp
about the lack of standard mechanisms for both threading and sockets in
Common Lisp (with the lispers arguing that it wasn't needed) I find it
"curious" that someone can say Common Lisp scales well.

You really need to get better at distinguishing between reality and
usenet flamewars. While some comp.lang.lispers were bitching back and
forth about this, others of us were in Hamburg listening to Martin
Cracauer from ITA talking about "Common Lisp in a high-performance
search environment". In case you aren't aware, ITA is the company
that makes the search engine behind Orbitz.
 
K

Ken Tilton

Adam said:
Ken said:
Alexander said:
[trimmed groups]




yes, but do not feel bad, everyone gets confused by the /analogy/ to
spreadsheets into thinking Cells /is/ a spreadsheet. In fact, for a brief
period I swore off the analogy because it was so invariably misunderstood.
Even Graham misunderstood it.


Count me in.

<g> But looking at what it says: "Think of the slots as cells in a
spreadsheet (get it?), and you've got the right idea. ", if you follow
the analogy (and know that slot means "data member" in other OO models)
you also know that Serge's Spreadsheet example would have scored a big
fat zero on the Miller Analogy Test. Serge in no way made slots in
Python classes behave like cells in a spreadsheet. He simply started
work on a Spreadsheet application, using Python classes along the way. Bzzt.

While everyone makes the mistake, it is only because few of us (me
included) read very carefully. Especially if they are more interested in
flaming than learning what someone is saying.


I don't really mean any disrespect here, but if an analogy is not
interpreted correctly by a large group of people, the analogy is crap,
not the people.

No, I do not think that follows. I reiterate: people (inluding me!) read
too quickly, and this analogy has a trap in it: spreadsheets are /also/
software.

The analogy is fine and the people are fine, but as you suggest there is
a human engineering problem to be acknowledged.

btw, I have a couple of links to papers on similar art and they all use
the spreadshett metaphor. It is too good not to, but...
Yes, I understood it, specifically because I have spent
enough time dinking around with cell functions in a spreadhseet to
understand what you meant.

Maybe it would help to change the wording to "functions with cell
references in a spreadsheet" instead of "cells in a spreadsheet".

<g> We could do a study. I doubt your change would work, but, hey, that
is what studies are for.

I think probably the best thing to do with the human engineering problem
is attack the misunderstanding explicitly. "Now if you are like most
people, you think that means X. It does not." And then give an example,
and then again say what it is not.

Anyone who comes away from /that/ with the wrong idea just is not trying.

But I would not put that in the project synopsis, and that is all the
original confused poster read. Just not trying.

kenny

--
Cells: http://common-lisp.net/project/cells/

"Have you ever been in a relationship?"
Attorney for Mary Winkler, confessed killer of her
minister husband, when asked if the couple had
marital problems.
 
D

David C. Ullrich

[...]

Your spreadsheet does not have slots ruled by functions, it has one slot
for a dictionary where you store names and values/formulas.

Go back to your example and arrange it so a and b are actual slots (data
members? fields?) of the spreadsheet class. You can just stuff numbers in a:

sheet1.a = 42

but b should be somehow associated with a rule when sheet1 is created.
As I said in the other post, also associate an on-change callback with
slots a and b.

I must be missing something - seems this should be easy using
__setattr__ and __getattr__. Then _literally_ there's just a
dict containing names and functions, but when you _use_ the
class it looks just like the above:
[...]

When that is done we can look at a working example and see how well
Python fared without macros and full-blown lambda.

No lambda in the non-programmer-half-hour implementation below.
You need to define a named function for each cell to use as
a callback. Except for that what are Cells supposed to do that
the implementation below doesn't do?

"""PyCells.py"""

class Cell:

def __init__(self, name, owner, callback):
self.name = name
self.callback = callback
self.owner = owner

def onchange(self, value):
self.value = value
self.callback(self, value)

class Cells:

def __init__(self):
#self.slots = {}
#Oops, don't work so well with __setattr__:
self.__dict__['slots'] = {}

def __setattr__(self, name, value):
self.slots[name].onchange(value)

def __getattr__(self, name):
return self.slots[name].value

def AddCell(self, name, callback):
self.slots[name] = Cell(name, self, callback)

***********

Sample use:

cells = Cells()

def acall(cell, value):
cell.owner.slots['b'].value = value + 1

cells.AddCell('a',acall)

def bcall(cell, value):
cell.owner.slots['a'].value = value - 1

cells.AddCell('b',bcall)

cells.a = 42
print cells.a, cells.b
cells.b = 24
print cells.a, cells.b

************************

David C. Ullrich
 
D

David C. Ullrich

[...]

def acall(cell, value):
cell.owner.slots['b'].value = value + 1

Needing to say that sort of thing every time
you define a callback isn't very nice.
New and improved version:

"""PyCells.py"""

class Cell:

def __init__(self, name, owner, callback):
self.name = name
self.callback = callback
self.owner = owner

def onchange(self, value):
self.value = value
self.callback(self, value)

def __setitem__(self, name, value):
self.owner.slots[name].value = value

class Cells:

def __init__(self):
self.__dict__['slots'] = {}

def __setattr__(self, name, value):
self.slots[name].onchange(value)

def __getattr__(self, name):
return self.slots[name].value

def AddCell(self, name, callback):
self.slots[name] = Cell(name, self, callback)

Sample:

cells = Cells()

def acall(cell, value):
cell['b'] = value + 1

cells.AddCell('a',acall)

def bcall(cell, value):
cell['a'] = value - 1

cells.AddCell('b',bcall)

cells.a = 42
print cells.a, cells.b
cells.b = 24
print cells.a, cells.b


#OR you could give Cell a __setattr__ so the above
#would be cell.a = value - 1. I think I like this
#version better; in applications I have in mind I
#might be iterating over lists of cell names.

************************

David C. Ullrich
 
K

Ken Tilton

David said:
[...]

Your spreadsheet does not have slots ruled by functions, it has one slot
for a dictionary where you store names and values/formulas.

Go back to your example and arrange it so a and b are actual slots (data
members? fields?) of the spreadsheet class. You can just stuff numbers in a:

sheet1.a = 42

but b should be somehow associated with a rule when sheet1 is created.
As I said in the other post, also associate an on-change callback with
slots a and b.


I must be missing something - seems this should be easy using
__setattr__ and __getattr__. Then _literally_ there's just a
dict containing names and functions, but when you _use_ the
class it looks just like the above:

Ah, but looks like is not enough. Suppose you have a GUI class from
Tkinter. After a little more playing and fixing the huge gap described
in the next paragraph you decide, Cripes! Kenny was right! This is very
powerful. So now you want to subclass a Tkinter button and control
whether it is enabled with a rule (the huge gap, btw). But the enabled
flag of the super class is a native Python class slot. How would you
handle that with your faux object system? Had you truly extended the
Python class system you could just give the inherited slot a rule.
Speaking of which...

btw, You claimed "no lambda" but I did not see you doing a ruled value
anywhere, and that is where you want the lambda. And in case you
thinking your callbacks do that.

No, you do not want on-change handlers propagating data to other slots,
though that is a sound albeit primitive way of improving
self-consistency of data in big apps. The productivity win with VisiCalc
was that one simply writes rules that use other cells, and the system
keeps track of what to update as any cell changes for you. You have that
exactly backwards: every slot has to know what other slots to update. Ick.


kenny

--
Cells: http://common-lisp.net/project/cells/

"Have you ever been in a relationship?"
Attorney for Mary Winkler, confessed killer of her
minister husband, when asked if the couple had
marital problems.
 

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,780
Messages
2,569,614
Members
45,290
Latest member
JennaNies

Latest Threads

Top