[trimmed groups] Ken Tilton <[EMAIL PROTECTED]> 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(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? > 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 printChangeBlurp(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 updateDependents(dependents): seen = {} for dependent in dependents: if dependent not in seen: seen[dependent] = True dependent.recalculate() updateDependents(dependent._dependents) class cell(object): def __init__(self, formula, dependsOn=(), onChange=None): self.formula = formula self.dependencies = dependsOn self.onChange = onChange self._val = _unbound for dependency in self.dependencies: if self not in dependency._dependents: dependency._dependents.append(self) self._dependents = [] def __str__(self): return str(self.val) def recalculate(self): newVal = self.formula() if self.onChange is not None: oldVal = self._val self.onChange(self, oldVal, newVal, oldVal is not _unbound) self._val = newVal def getVal(self): if self._val is _unbound: self.recalculate() return self._val def setVal(self, value): self._val = value updateDependents(self._dependents) val = property(getVal, setVal) 'as -- http://mail.python.org/mailman/listinfo/python-list