473,769 Members | 2,081 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

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

Python, Lambda, and Guido van Rossum

Xah Lee, 2006-05-05

In this post, i'd like to deconstruct one of Guido's recent blog about
lambda in Python.

In Guido's blog written in 2006-02-10 at
http://www.artima.com/weblogs/viewpo...?thread=147358

is first of all, the title “Language Design Is Not Just Solving
Puzzles”. In the outset, and in between the lines, we are told that
“I'm the supreme intellect, and I created Python”.

This seems impressive, except that the tech geekers due to their
ignorance of sociology as well as lack of analytic abilities of the
mathematician, do not know that creating a language is a act that
requires little qualifications. However, creating a language that is
used by a lot people takes considerable skill, and a big part of that
skill is salesmanship. Guido seems to have done it well and seems to
continue selling it well, where, he can put up a title of belittlement
and get away with it too.

Gaudy title aside, let's look at the content of his say. If you peruse
the 700 words, you'll find that it amounts to that Guido does not like
the suggested lambda fix due to its multi-line nature, and says that he
don't think there could possibly be any proposal he'll like. The
reason? Not much! Zen is bantered about, mathematician's impractical
ways is waved, undefinable qualities are given, human's right brain is
mentioned for support (neuroscience!) , Rube Goldberg contrivance
phraseology is thrown, and coolness of Google Inc is reminded for the
tech geekers (in juxtaposition of a big notice that Guido works
there.).

If you are serious, doesn't this writing sounds bigger than its
content? Look at the gorgeous ending: “This is also the reason why
Python will never have continuations, and even why I'm uninterested in
optimizing tail recursion. But that's for another installment.” . This
benevolent geeker is gonna give us another INSTALLMENT!

There is a computer language leader by the name of Larry Wall, who said
that “The three chief virtues of a programmer are: Laziness,
Impatience and Hubris” among quite a lot of other ingenious
outpourings. It seems to me, the more i learn about Python and its
leader, the more similarities i see.

So Guido, i understand that selling oneself is a inherent and necessary
part of being a human animal. But i think the lesser beings should be
educated enough to know that fact. So that when minions follow a
leader, they have a clear understanding of why and what.

----

Regarding the lambda in Python situation... conceivably you are right
that Python lambda is perhaps at best left as it is crippled, or even
eliminated. However, this is what i want: I want Python literatures,
and also in Wikipedia, to cease and desist stating that Python supports
functional programing. (this is not necessarily a bad publicity) And, I
want the Perl literatures to cease and desist saying they support OOP.
But that's for another installment.

----
This post is archived at:
http://xahlee.org/UnixResource_dir/w...bda_guido.html

* * Xah
* * xa*@xahlee.org
http://xahlee.org/

May 6 '06
267 10829
Bill Atkins <NO**********@r pi.edu> writes:
There are still more! _On Lisp_ has a lot of interesting ones, like
an embedded Prolog interpreter and compiler:

(<-- (father billsr billjr))
(?- (father billsr ?))

? = billjr


Actually, these might not be implemented as macros.

--
This is a song that took me ten years to live and two years to write.
- Bob Dylan
May 7 '06 #91
Ken Tilton <ke*******@gmai l.com> writes:
As for:
At a syntax-sugar
level, for example, Lisp's choice to use parentheses as delimiter means
it's undesirable, even unfeasible, to use the single character '(' as an
ordinary identifier in a future release of the language.
(defun |(| (aside) (format nil "Parentheticall y speaking...~a." aside))
=> |(|
(|(| "your Lisp /is/ rusty.")
=> "Parentheticall y speaking...your Lisp /is/ rusty.."

:) No, seriously, is that all you can come up with?


Well, you have to quote your (s-as-identifiers. I tried a goofy hack
of a reader macro for ( to make this parse:

(let (( ( 10))) ( ))

[The spaces are just for readability, not necessary]

Alas, short of cps-transforming the whole reader, I can't see a
reasonable way to get that to parse as a single sexp that, when
evaluated, returns 10. What my reader macro gave me was five sexps:

\(, LET, \(, ((10)), NIL

I'll follow up with the Lisp code (on c.l.l only), in case I'm missing
something simple.
OK, I propose a duel. We'll co-mentor this:

http://www.lispnyc.org/wiki.clp?page=PyCells

In the end Python will have a Silver Bullet, and only the syntax will
differ, because Python has a weak lambda, statements do not always
return values, it does not have macros, and I do not know if it has
special variables.


I have no idea what the big problem with a multi-line lambda is in
Python, but I wonder if Cells wouldn't run against the same thing. I
often pass around anonymous formulas that eventually get installed in
a slot. Seems annoying to have to name every formula with a
labels-like mechanism.
May 7 '06 #92


Serge Orlov wrote:
Ken Tilton wrote:
It is vastly more disappointing that an alleged tech genius would sniff
at the chance to take undeserved credit for PyCells, something probably
better than a similar project on which Adobe (your superiors at
software, right?) has bet the ranch. This is the Grail, dude, Brooks's
long lost Silver Bullet. And you want to pass?????

C'mon, Alex, I just want you as co-mentor for your star quality. Of
course you won't have to do a thing, just identify for me a True Python
Geek and she and I will take it from there.

Here's the link in case you lost it:

http://www.lispnyc.org/wiki.clp?page=PyCells

:)

peace, kenny

ps. flaming aside, PyCells really would be amazingly good for Python.
And so Google. (Now your job is on the line. <g>) k

Perhaps I'm missing something...


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.

But it is such a great analogy! <sigh>
but what's the big deal about PyCells?
Here is 22-lines barebones implementation of spreadsheet in Python,
later I create 2 cells "a" and "b", "b" depends on a and evaluate all
the cells. The output is

a = negate(sin(pi/2)+one) = -2.0
b = negate(a)*10 = 20.0


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(n egate(sin(pi/2)+v1)
b = determined_by(n egate(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

The other thing we want is (really inventing syntax here):

on_change(a,new ,old,old-bound?) print(list(new, old, old-bound?)

Then the print statements Just Happen. ie, It is not as if we are just
hiding computed variables behind syntax and computations get kicked off
when a value is read. Instead, an underlying engine propagates any
assignment throughout the dependency graph before the assignment returns.

My Cells hack does the above, not with global variables, but with slots
(data members?) of instances in the CL object system. I have thought
about doing it with global variables such as a and b above, but never
really seen much of need, maybe because I like OO and can always think
of a class to create of which the value should be just one attribute.

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.
May 7 '06 #93


Serge Orlov wrote:
Bill Atkins wrote:
"Serge Orlov" <Se*********@gm ail.com> writes:

Ken Tilton wrote:

It is vastly more disappointing that an alleged tech genius would sniff
at the chance to take undeserved credit for PyCells, something probably
better than a similar project on which Adobe (your superiors at
software, right?) has bet the ranch. This is the Grail, dude, Brooks's
long lost Silver Bullet. And you want to pass?????

C'mon, Alex, I just want you as co-mentor for your star quality. Of
course you won't have to do a thing, just identify for me a True Python
Geek and she and I will take it from there.

Here's the link in case you lost it:

http://www.lispnyc.org/wiki.clp?page=PyCells

:)

peace, kenny

ps. flaming aside, PyCells really would be amazingly good for Python.
And so Google. (Now your job is on the line. <g>) k

Perhaps I'm missing something but what's the big deal about PyCells?
Here is 22-lines barebones implementation of spreadsheet in Python,
later I create 2 cells "a" and "b", "b" depends on a and evaluate all
the cells. The output is

a = negate(sin(pi/2)+one) = -2.0
b = negate(a)*10 = 20.0

============ ======= spreadsheet.py =============== ===
class Spreadsheet(dic t):
def __init__(self, **kwd):
self.namespace = kwd
def __getitem__(sel f, cell_name):
item = self.namespace[cell_name]
if hasattr(item, "formula"):
return item()
return item
def evaluate(self, formula):
return eval(formula, self)
def cell(self, cell_name, formula):
"Create a cell defined by formula"
def evaluate_cell() :
return self.evaluate(f ormula)
evaluate_cell.f ormula = formula
self.namespace[cell_name] = evaluate_cell
def cells(self):
"Yield all cells of the spreadsheet along with current values
and formulas"
for cell_name, value in self.namespace. items():
if not hasattr(value, "formula"):
continue
yield cell_name, self[cell_name], value.formula

import math
def negate(x):
return -x
sheet1 = Spreadsheet(one =1, sin=math.sin, pi=math.pi, negate=negate)
sheet1.cell( "a", "negate(sin (pi/2)+one)")
sheet1.cell( "b", "negate(a)* 10")
for name, value, formula in sheet1.cells():
print name, "=", formula, "=", value

I hope Ken doesn't mind me answering for him, but Cells is not a
spreadsheet (where did you get that idea?).

It's written on the page linked above, second sentence: "Think of the
slots as cells in a spreadsheet, and you've got the right idea". I'm
not claiming that my code is full PyCell implementation.


Well it's the Miller Analogy Test, isn't it? <g> Very easy to leave out
a level of abstraction. Like I said in my other reply, /everyone/ leaves
this level out.

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.

When you create sheet1:

sheet1 = Spreadsheet(a=4 2,b=pow(self.a, 2))

You should see the callbacks for a and b fire. Then when you:

sheet1.a = 7

You should see them fire again (and each should see old and new values
as one would hope).

The fun part is when the rule associated with b is just:

self.b = somefunction(se lf)

and somefunction happens to access slot a and it all still works.

One important feature above is that the rule is associated with the slot
when the instance is created, and different instances can have different
ruls for the same slot. In effect, classes become programmable, hence
more reusable -- without this one is forever subclassing to satisfy
different functional requirements.


It does apply the basic
idea of a spreadsheet to software - that is, instead of updating value
when some event occurs, you specify in advance how that value can be
computed and then you stop worrying about keeping it updated.

The result is the same.


Hopefully I have made clear the different levels. With your example, all
variables exist only in the universe of the Spreadsheet class. So you
have a good start on an /interpreter/ that works like the /extension/
Cells provide to Common Lisp.

Do you see the difference?

Apologies for all the pseudo-Python above, btw.

btw, I am not saying Python cannot do PyCells. I got pretty far on a
port from CL to Python before losing interest. You just take your code
above and move it to the metaclass level and, yes, track dependencies,
etc etc etc.

When that is done we can look at a working example and see how well
Python fared without macros and full-blown lambda.
hth, 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.
May 7 '06 #94


Thomas F. Burdick wrote:
Ken Tilton <ke*******@gmai l.com> writes:

As for:

At a syntax-sugar
level, for example, Lisp's choice to use parentheses as delimiter means
it's undesirable, even unfeasible, to use the single character '(' as an
ordinary identifier in a future release of the language.
(defun |(| (aside) (format nil "Parentheticall y speaking...~a." aside))
=> |(|
(|(| "your Lisp /is/ rusty.")
=> "Parentheticall y speaking...your Lisp /is/ rusty.."

:) No, seriously, is that all you can come up with?

Well, you have to quote your (s-as-identifiers. I tried a goofy hack
of a reader macro for ( to make this parse:

(let (( ( 10))) ( ))

[The spaces are just for readability, not necessary]

Alas, short of cps-transforming the whole reader, I can't see a
reasonable way to get that to parse as a single sexp that, when
evaluated, returns 10. What my reader macro gave me was five sexps:

\(, LET, \(, ((10)), NIL

I'll follow up with the Lisp code (on c.l.l only), in case I'm missing
something simple.


Stop, you are scaring the pythonistas. Even Alex thought I was serious
with (|(| "Hi mom"). Ouch that is hard to type.


OK, I propose a duel. We'll co-mentor this:

http://www.lispnyc.org/wiki.clp?page=PyCells

In the end Python will have a Silver Bullet, and only the syntax will
differ, because Python has a weak lambda, statements do not always
return values, it does not have macros, and I do not know if it has
special variables.

I have no idea what the big problem with a multi-line lambda is in
Python, but I wonder if Cells wouldn't run against the same thing. I
often pass around anonymous formulas that eventually get installed in
a slot. Seems annoying to have to name every formula with a
labels-like mechanism.


(a) Right.

(b) Bloated syntax will hurt in a linear way. the decomposition of
application complexity into so many tractable small rules is a nonlinear
win. (ok, painful coding of X does diminish ones use of X, but Cells
force one to use Cells everywhere or not at all, so it comes with its
own press gang, er, discipline.)

(c) (b) might convince GvR to fix (a)

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.
May 7 '06 #95


Ken Tilton wrote:

a = negate(sin(pi/2)+one) = -2.0
b = negate(a)*10 = 20.0

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


Sorry, only later did I realize "one" was going in as a named
spreadsheet Cell. I thought maybe Python was a bit of a super-cobol and
had one as a keyword. <g>

kenny
May 7 '06 #96


Ken Tilton wrote:


Serge Orlov wrote:
Ken Tilton wrote:
It is vastly more disappointing that an alleged tech genius would sniff
at the chance to take undeserved credit for PyCells, something probably
better than a similar project on which Adobe (your superiors at
software, right?) has bet the ranch. This is the Grail, dude, Brooks's
long lost Silver Bullet. And you want to pass?????

C'mon, Alex, I just want you as co-mentor for your star quality. Of
course you won't have to do a thing, just identify for me a True Python
Geek and she and I will take it from there.

Here's the link in case you lost it:

http://www.lispnyc.org/wiki.clp?page=PyCells

:)

peace, kenny

ps. flaming aside, PyCells really would be amazingly good for Python.
And so Google. (Now your job is on the line. <g>) k


Perhaps I'm missing something...

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.

But it is such a great analogy! <sigh>
but what's the big deal about PyCells?
Here is 22-lines barebones implementation of spreadsheet in Python,
later I create 2 cells "a" and "b", "b" depends on a and evaluate all
the cells. The output is

a = negate(sin(pi/2)+one) = -2.0
b = negate(a)*10 = 20.0

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(n egate(sin(pi/2)+v1)
b = determined_by(n egate(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

The other thing we want is (really inventing syntax here):

on_change(a,new ,old,old-bound?) print(list(new, old, old-bound?)

Then the print statements Just Happen. ie, It is not as if we are just
hiding computed variables behind syntax and computations get kicked off
when a value is read. Instead, an underlying engine propagates any
assignment throughout the dependency graph before the assignment returns.

My Cells hack does the above, not with global variables, but with slots
(data members?) of instances in the CL object system.


here it is:

(in-package :cells)

(defmodel useless () ;; defmodel is CLOS defclass plus Cells wiring
((one :initform nil :accessor one :initarg :one)
(a :initform nil :accessor a :initarg :a)
(b :initform nil :accessor b :initarg :b)))

;; defobserver defines a CLOS method just the right way

(defobserver one (self new-value old-value old-value-bound-p)
(print (list :observing-one new-value old-value old-value-bound-p)))

(defobserver a (self new-value old-value old-value-bound-p)
(print (list :observing-a new-value old-value old-value-bound-p)))

(defobserver b (self new-value old-value old-value-bound-p)
(print (list :observing-b new-value old-value old-value-bound-p)))

;; c-in and c? hide more Cells wiring. The long names are c-input and
c-formula, btw

(progn
(print :first-we-make-a-useless-instance)
(let ((u (make-instance 'useless
:one (c-in 1) ;; we want to change it later, so wrap as
input value
:a (c? (- (+ (sin (/ pi 2)) (one self)))) ;;
negate(sin(pi/2)+one)
:b (c? (* (- (a self) 10)))))) ;; negate(a)*10
(print :now-we-change-one-to-ten)
(setf (one u) 10)))

#| output of the above

:first-we-make-a-useless-instance
(:observing-one 1 nil nil)
(:observing-a -2.0d0 nil nil)
(:observing-b -12.0d0 nil nil)
:now-we-change-one-to-ten
(:observing-one 10 1 t)
(:observing-a -11.0d0 -2.0d0 t)
(:observing-b -21.0d0 -12.0d0 t)

|#

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.
May 7 '06 #97
[trimmed groups]

Ken Tilton <ke*******@gmai l.com> writes:
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.

But it is such a great analogy! <sigh>
but what's the big deal about PyCells?
Here is 22-lines barebones implementation of spreadsheet in Python,
later I create 2 cells "a" and "b", "b" depends on a and evaluate all
the cells. The output is
a = negate(sin(pi/2)+one) = -2.0
b = negate(a)*10 = 20.0


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(n egate(sin(pi/2)+v1)
b = determined_by(n egate(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: printChangeBlur p(name='b',*arg s))
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__.unbou nd 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?
The other thing we want is (really inventing syntax here):

on_change(a,new ,old,old-bound?) print(list(new, old, old-bound?)
Is the above what you want (you can also dynamically assign onChange later
on, as required or have a list of procedures instead)?

Then the print statements Just Happen. ie, It is not as if we are just hiding
computed variables behind syntax and computations get kicked off when a value
is read. Instead, an underlying engine propagates any assignment throughout
the dependency graph before the assignment returns.
Updating on write rather than recalculating on read does in itself not seem
particularly complicated.
My Cells hack does the above, not with global variables, but with slots (data
members?) of instances in the CL object system. I have thought about doing it
with global variables such as a and b above, but never really seen much of
need, maybe because I like OO and can always think of a class to create of
which the value should be just one attribute.


OK, so in what way does the quick 35 line hack below also completely miss your
point?
# (NB. for lispers: 'is' == EQ; '==' is sort of like EQUAL)

def printChangeBlur p(someCell, oldVal, newVal, bound, name=''):
print '[cell %r changed from %r to %r, it was %s]' % (
name, oldVal, newVal, ['not bound', 'bound '][bound]),

_unbound = type('unbound', (), {})() # just an unique dummy value
def updateDependent s(dependents):
seen = {}
for dependent in dependents:
if dependent not in seen:
seen[dependent] = True
dependent.recal culate()
updateDependent s(dependent._de pendents)
class cell(object):
def __init__(self, formula, dependsOn=(), onChange=None):
self.formula = formula
self.dependenci es = dependsOn
self.onChange = onChange
self._val = _unbound
for dependency in self.dependenci es:
if self not in dependency._dep endents:
dependency._dep endents.append( self)
self._dependent s = []
def __str__(self):
return str(self.val)
def recalculate(sel f):
newVal = self.formula()
if self.onChange is not None:
oldVal = self._val
self.onChange(s elf, oldVal, newVal, oldVal is not _unbound)
self._val = newVal
def getVal(self):
if self._val is _unbound:
self.recalculat e()
return self._val
def setVal(self, value):
self._val = value
updateDependent s(self._depende nts)
val = property(getVal , setVal)

'as
May 7 '06 #98
Alexander Schmolck <a.********@gma il.com> writes:
[trimmed groups]

Ken Tilton <ke*******@gmai l.com> writes:
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.

But it is such a great analogy! <sigh>
> but what's the big deal about PyCells?
> Here is 22-lines barebones implementation of spreadsheet in Python,
> later I create 2 cells "a" and "b", "b" depends on a and evaluate all
> the cells. The output is
> a = negate(sin(pi/2)+one) = -2.0

> b = negate(a)*10 = 20.0


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(n egate(sin(pi/2)+v1)
b = determined_by(n egate(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: printChangeBlur p(name='b',*arg s))
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__.unbou nd 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?
The other thing we want is (really inventing syntax here):

on_change(a,new ,old,old-bound?) print(list(new, old, old-bound?)


Is the above what you want (you can also dynamically assign onChange later
on, as required or have a list of procedures instead)?

Then the print statements Just Happen. ie, It is not as if we are just hiding
computed variables behind syntax and computations get kicked off when a value
is read. Instead, an underlying engine propagates any assignment throughout
the dependency graph before the assignment returns.


Updating on write rather than recalculating on read does in itself not seem
particularly complicated.
My Cells hack does the above, not with global variables, but with slots (data
members?) of instances in the CL object system. I have thought about doing it
with global variables such as a and b above, but never really seen much of
need, maybe because I like OO and can always think of a class to create of
which the value should be just one attribute.


OK, so in what way does the quick 35 line hack below also completely miss your
point?
# (NB. for lispers: 'is' == EQ; '==' is sort of like EQUAL)

def printChangeBlur p(someCell, oldVal, newVal, bound, name=''):
print '[cell %r changed from %r to %r, it was %s]' % (
name, oldVal, newVal, ['not bound', 'bound '][bound]),

_unbound = type('unbound', (), {})() # just an unique dummy value
def updateDependent s(dependents):
seen = {}
for dependent in dependents:
if dependent not in seen:
seen[dependent] = True
dependent.recal culate()
updateDependent s(dependent._de pendents)
class cell(object):
def __init__(self, formula, dependsOn=(), onChange=None):
self.formula = formula
self.dependenci es = dependsOn
self.onChange = onChange
self._val = _unbound
for dependency in self.dependenci es:
if self not in dependency._dep endents:
dependency._dep endents.append( self)
self._dependent s = []
def __str__(self):
return str(self.val)
def recalculate(sel f):
newVal = self.formula()
if self.onChange is not None:
oldVal = self._val
self.onChange(s elf, oldVal, newVal, oldVal is not _unbound)
self._val = newVal
def getVal(self):
if self._val is _unbound:
self.recalculat e()
return self._val
def setVal(self, value):
self._val = value
updateDependent s(self._depende nts)
val = property(getVal , setVal)

'as


Here's how one of the cells examples might look in corrupted Python
(this is definitely not executable):

class FallingRock:
def __init__(self, pos):
define_slot( 'velocity', lambda: self.accel * self.elapsed )
define_slot( 'pos', lambda: self.accel * (self.elapsed ** 2) / 2,
initial_positio n = cell_initial_va lue( 100 ) )
self.accel = -9.8

rock = FallingRock(100 )
print rock.accel, rock.velocity, rock.pos
# -9.8, 0, 100

rock.elapsed = 1
print rock.accel, rock.velocity, rock.pos
# -9.8, -9.8, -9.8

rock.elapsed = 8
print rock.accel, rock.velocity, rock.pos
# -9.8, -78.4, -627.2

Make sense? The idea is to declare what a slot's value represents
(with code) and then to stop worrying about keeping different things
synchronized.

Here's another of the examples, also translated into my horrific
rendition of Python (forgive me):

class Menu:
def __init__(self):
define_slot( 'enabled',
lambda: focused_object( self ).__class__ == TextEntry and
focused_object( self ).selection )

Now whenever the enabled slot is accessed, it will be calculated based
on what object has the focus. Again, it frees the programmer from
having to keep these different dependencies updated.

--
This is a song that took me ten years to live and two years to write.
- Bob Dylan
May 7 '06 #99
Bill Atkins <NO**********@r pi.edu> writes:
Alexander Schmolck <a.********@gma il.com> writes:
[trimmed groups]

Ken Tilton <ke*******@gmai l.com> writes:
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.

But it is such a great analogy! <sigh>

> but what's the big deal about PyCells?
> Here is 22-lines barebones implementation of spreadsheet in Python,
> later I create 2 cells "a" and "b", "b" depends on a and evaluate all
> the cells. The output is
> a = negate(sin(pi/2)+one) = -2.0

> b = negate(a)*10 = 20.0

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(n egate(sin(pi/2)+v1)
b = determined_by(n egate(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: printChangeBlur p(name='b',*arg s))
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__.unbou nd 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?
The other thing we want is (really inventing syntax here):

on_change(a,new ,old,old-bound?) print(list(new, old, old-bound?)


Is the above what you want (you can also dynamically assign onChange later
on, as required or have a list of procedures instead)?

Then the print statements Just Happen. ie, It is not as if we are just hiding
computed variables behind syntax and computations get kicked off when a value
is read. Instead, an underlying engine propagates any assignment throughout
the dependency graph before the assignment returns.


Updating on write rather than recalculating on read does in itself not seem
particularly complicated.
My Cells hack does the above, not with global variables, but with slots (data
members?) of instances in the CL object system. I have thought about doing it
with global variables such as a and b above, but never really seen much of
need, maybe because I like OO and can always think of a class to create of
which the value should be just one attribute.


OK, so in what way does the quick 35 line hack below also completely miss your
point?
# (NB. for lispers: 'is' == EQ; '==' is sort of like EQUAL)

def printChangeBlur p(someCell, oldVal, newVal, bound, name=''):
print '[cell %r changed from %r to %r, it was %s]' % (
name, oldVal, newVal, ['not bound', 'bound '][bound]),

_unbound = type('unbound', (), {})() # just an unique dummy value
def updateDependent s(dependents):
seen = {}
for dependent in dependents:
if dependent not in seen:
seen[dependent] = True
dependent.recal culate()
updateDependent s(dependent._de pendents)
class cell(object):
def __init__(self, formula, dependsOn=(), onChange=None):
self.formula = formula
self.dependenci es = dependsOn
self.onChange = onChange
self._val = _unbound
for dependency in self.dependenci es:
if self not in dependency._dep endents:
dependency._dep endents.append( self)
self._dependent s = []
def __str__(self):
return str(self.val)
def recalculate(sel f):
newVal = self.formula()
if self.onChange is not None:
oldVal = self._val
self.onChange(s elf, oldVal, newVal, oldVal is not _unbound)
self._val = newVal
def getVal(self):
if self._val is _unbound:
self.recalculat e()
return self._val
def setVal(self, value):
self._val = value
updateDependent s(self._depende nts)
val = property(getVal , setVal)

'as


Here's how one of the cells examples might look in corrupted Python
(this is definitely not executable):

class FallingRock:
def __init__(self, pos):
define_slot( 'velocity', lambda: self.accel * self.elapsed )
define_slot( 'pos', lambda: self.accel * (self.elapsed ** 2) / 2,
initial_positio n = cell_initial_va lue( 100 ) )
self.accel = -9.8

rock = FallingRock(100 )
print rock.accel, rock.velocity, rock.pos
# -9.8, 0, 100

rock.elapsed = 1
print rock.accel, rock.velocity, rock.pos
# -9.8, -9.8, -9.8

rock.elapsed = 8
print rock.accel, rock.velocity, rock.pos
# -9.8, -78.4, -627.2

Make sense? The idea is to declare what a slot's value represents
(with code) and then to stop worrying about keeping different things
synchronized.

Here's another of the examples, also translated into my horrific
rendition of Python (forgive me):

class Menu:
def __init__(self):
define_slot( 'enabled',
lambda: focused_object( self ).__class__ == TextEntry and
focused_object( self ).selection )

Now whenever the enabled slot is accessed, it will be calculated based
on what object has the focus. Again, it frees the programmer from
having to keep these different dependencies updated.

--
This is a song that took me ten years to live and two years to write.
- Bob Dylan


Oh dear, there were a few typos:

class FallingRock:
def __init__(self, pos):
define_slot( 'velocity', lambda: self.accel * self.elapsed )
define_slot( 'pos', lambda: self.accel * (self.elapsed ** 2) / 2,
initial_value = cell_initial_va lue( 100 ) )
self.accel = -9.8

rock = FallingRock(100 )
print rock.accel, rock.velocity, rock.pos
# -9.8, 0, 100

rock.elapsed = 1
print rock.accel, rock.velocity, rock.pos
# -9.8, -9.8, 90.2

rock.elapsed = 8
print rock.accel, rock.velocity, rock.pos
# -9.8, -78.4, -527.2

--
This is a song that took me ten years to live and two years to write.
- Bob Dylan
May 7 '06 #100

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

181
8911
by: Tom Anderson | last post by:
Comrades, During our current discussion of the fate of functional constructs in python, someone brought up Guido's bull on the matter: http://www.artima.com/weblogs/viewpost.jsp?thread=98196 He says he's going to dispose of map, filter, reduce and lambda. He's going to give us product, any and all, though, which is nice of him.
30
2173
by: Mike Meyer | last post by:
I know, lambda bashing (and defending) in the group is one of the most popular ways to avoid writing code. However, while staring at some Oz code, I noticed a feature that would seem to make both groups happy - if we can figure out how to avoid the ugly syntax. This proposal does away with the well-known/obscure "lambda" keyword. It gives those who want a more functional lambda what they want. It doesn't add any new keywords. It doesn't...
0
9589
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, well explore What is ONU, What Is Router, ONU & Routers main usage, and What is the difference between ONU and Router. Lets take a closer look ! Part I. Meaning of...
0
9423
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
0
10049
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth. The Art of Business Website Design Your website is...
1
9997
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
0
9865
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
0
8873
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development projectplanning, coding, testing, and deploymentwithout human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own.... Now, this would greatly impact the work of software developers. The idea...
0
5310
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
0
5448
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
3
2815
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.