Lambda the Ultimate

inactiveTopic Python 2.3 Release Schedule
started 10/12/2002; 8:28:37 AM - last post 10/15/2002; 11:31:01 AM
Ehud Lamm - Python 2.3 Release Schedule  blueArrow
10/12/2002; 8:28:37 AM (reads: 2779, responses: 14)
Python 2.3 Release Schedule
(via GIGO)

Some things that may be of special interest to LtU readers:

  • Add a new concept, "pending deprecation". Is this good language design?
  • Adding a Built-In Set Object Type
  • An iterator tools module featuring goodies from SML and Haskell?
  • Add support for the long-awaited Python catalog.
  • Pgen Module for Python. This PEP proposes that the parser generator used to create the Python parser, pgen, be exposed as a module in Python.


Posted to Python by Ehud Lamm on 10/12/02; 8:29:15 AM

Dan Shappir - Re: Python 2.3 Release Schedule  blueArrow
10/12/2002; 2:16:15 PM (reads: 1308, responses: 2)
This is the usual time for me to point out that all said goodies from SML and Haskell are already available in BeyondJS, e.g.:

ia = itertools.iter(open('readme.txt')) => ia = File.from('readme.txt')
ia[4] => ia.slice(4, 1)
ia[0] => ia.head()
ia[:10] => ia.tail(10)
ia[5:] => ia.head(5)
ia.filter(pred) => ia.filter(pred)
ia.map(func) => ia.foreach(func)

etc.

Ehud Lamm - Re: Python 2.3 Release Schedule  blueArrow
10/12/2002; 3:01:55 PM (reads: 1344, responses: 0)
I guess we all know this by now...

Dan Shappir - Re: Python 2.3 Release Schedule  blueArrow
10/13/2002; 1:06:30 AM (reads: 1265, responses: 2)
Obviously :-)

But forgive me for still finding it so cool that I could add all this new functionality to ECMAScript without having to rewrite the compiler/interpreter. Yes, ECMAScript does support functions as first class citizens and closures, but it doesn't intrinsically have lazy evaluation or unbound lists, or functional combinators. It doesn't even have macros. And yet it proved flexible enough for all this stuff to be added on as a library.

That cannot be said about Python or Perl etc.

pixel - Re: Python 2.3 Release Schedule  blueArrow
10/13/2002; 3:31:56 AM (reads: 1299, responses: 0)
?? Isn't itertools a python library? AFAIK all this can be done in Python or Perl (please give an example that can't :)

Bryn Keller - Re: Python 2.3 Release Schedule  blueArrow
10/14/2002; 9:51:01 AM (reads: 1217, responses: 0)
> That cannot be said about Python or Perl etc.

Are you sure? Seems to me my Xoltar Toolkit for Python (LTU reference) is roughly equivalent to BeyondJS based on the examples you've posted here from time to time.

I'm not saying BeyondJS isn't cool, or that ECMAScript isn't cool, just that I'm not sure ECMAScript is much more flexible than other scripting languages.

Dan Shappir - Re: Python 2.3 Release Schedule  blueArrow
10/15/2002; 3:13:01 AM (reads: 1161, responses: 7)
Like everybody else I have my own biases. Guess that as long as they are mostly limited to PLs I'm pretty much OK ;-) In other words, I did not mean to dis Python or Perl, sorry.

Isn't itertools a python library?

Yes it is, my point was that Python had to be extended with just this kind of functionality in mind in order to make such a library possible. That is, until generators were introduced in Python 2.2 I don't think you could have developed an effective iterator library.

BeyondJS OTOH was accomplished without any change to the underlying PL. Indeed, it was our stated goal to support as many versions of JavaScript as possible. Currently BeyondJS works on Mozilla, NS6 and IE5.5+, most of it works on IE4 and much also works on NS4.x. While all these versions of JavaScript have some functional capabilities, I don't think the following sample from BeyondJS was envisioned by the language creators:

// Sieve of Eratosthenes
function sieve(l) {
  return l.head(1).extend(sieve.using(l.tail().filter("%".curry([,l.head()]))));
}
var primes = sieve((2).lazy());
alert(primes.head(25));

BTW this code was inspired by the following Mondrian sample:

// sieve : List<Integer> -> List<Integer>;
sieve = xs ->
  switch (xs)
  { case (y::ys):
    y :: sieve (filter (x -> x % y != 0) ys);
  };
primes = sieve (from 2);

Seems to me my Xoltar Toolkit for Python (LTU reference) is roughly equivalent to BeyondJS based on the examples you've posted here from time to time.

Sure looks like it. Seems like a very cool lib. Do you use generators?

pixel - Re: Python 2.3 Release Schedule  blueArrow
10/15/2002; 6:09:34 AM (reads: 1158, responses: 3)

# Yes it is, my point was that Python had to be extended with just this kind of functionality in mind in order to make such a library possible. That is, until generators were introduced in Python 2.2 I don't think you could have developed an effective iterator library.

Well, you could develop an iterator library. As for effective, the main problem is the "lambda" limitation in python (which disallows statements). Python 2.2 introduces iterators in "for ... in ..." which doesn't have the no-statement restriction. But this doesn't unleash the full power of the language.

Such a library is easily done in Perl or Ruby, with more-or-less syntactical help.

# Sure looks like it. Seems like a very cool lib. Do you use generators?

me? I try to avoid Python ;p

As for Javascript, I wish there were a simple to use standalone interpreter... Hum wait, google says ngs-js is available... Cool, at last I'm able to test it :)

Ehud Lamm - Re: Python 2.3 Release Schedule  blueArrow
10/15/2002; 6:54:58 AM (reads: 1204, responses: 2)
I am not sure I understand what you guys are talking about. Are you talking anbout the lack of closures?

pixel - Re: Python 2.3 Release Schedule  blueArrow
10/15/2002; 9:27:13 AM (reads: 1248, responses: 1)

# I am not sure I understand what you guys are talking about. Are you talking anbout the lack of closures?

nope. about the lack of anonymous functions which can use statements. In Ruby (dumb example):

s = 0
l = [1, 2, 3].map{|e|
  s += e
  2 * e
}
p l, s

This can't be done in Python without:

  • defining a function
  • or using the "for ... in ..." construct and forgetting about using functional constructs like fold, map, filter...

Bryn Keller - Re: Python 2.3 Release Schedule  blueArrow
10/15/2002; 10:12:02 AM (reads: 1181, responses: 2)
Yes it is, my point was that Python had to be extended with just this kind of functionality in mind in order to make such a library possible. That is, until generators were introduced in Python 2.2 I don't think you could have developed an effective iterator library.

I'm not so sure. I think itertools could have been developed at any time (from Python 1.52 on, say) to work with Python's older pre-iterators: sequences. Just as Haskell's takeWhile works on lists, so could an itertools-alike module work with Python sequences. Iterators are not necessary to play this game.

The question of whether iterators are possible without extending the language is also simple to answer in the affirmative. Consider this "iterator", which would have worked under 1.52:

class Fibs:
    def __init__(self):
        self.value1 = 1
        self.value2 = 1
    def __getitem__(self, i):
        if i < 0:
            raise IndexError
        val = self.value1
        self.value1 = self.value2
        self.value2 = val + self.value2
        return val
This is the traditional OO way of making an iterator. For more functional iterators, you could have used the 'closure' function from functional.py (I don't think it's there in the current version anymore, since it's irrelevant after Python 2.1) to fake a real closure.

How? In Python < 2.1, there are only 3 scopes: local, module (called 'global'), and builtin. My closure() function took a function as input, and returned a new function with the same code, but with its module scope set to a new dictionary which had the locals of the enclosing function plus the globals of the enclosing function - instant closure! The limitation was that the new function essentially has a module all to itself, so changes to module bindings would be missed. That is:

x = 5
def foo():
    global x
    x = x + 1

def bar(): y = 5 def baz(): return x + y

adder = bar() foo() foo() res = adder()

Now res will be 10, not 12, because baz is working on a copy of the module's environment as it was when we called bar(), not on the 'real' module environment. Changes to bound objects (rather than the bindings themselves) would of course be seen by both.

There's also the question of lazy lists and so on, which neither the language or the standard library currently address, but which were possible to implement even in Python 1.52 - see lazy.py in the Xoltar Toolkit.

So, Python (even in 1.52 days) was highly susceptible of customization in ways its creators don't even approve of (Guido seems not to be awfully fond of functional programming, e.g.). Python's generators are neat and all, but they're really just saving you the work of writing a class which saves some state in between calls. It's not rocket science. :-)

Sure looks like it. Seems like a very cool lib. Do you use generators?

Thanks, it was fun to write. No generators, since it was originally for Python 1.52 (now 2.1). I have a version of lazy.py at home which adds support for lazy lists constructed from generators, but that's about it. :-)

Bryn Keller - Re: Python 2.3 Release Schedule  blueArrow
10/15/2002; 10:29:11 AM (reads: 1278, responses: 0)
s = 0
l = [1, 2, 3].map{|e|
  s += e
  2 * e
}
p l, s

This can't be done in Python without:

* defining a function * or using the "for ... in ..." construct and forgetting about using functional constructs like fold, map, filter...

It's usually possible to get around this sort of thing too, though admittedly painful.
>>> s = 0
>>> l = map(lambda e:globals().update({'s':globals().get('s') + e}) or 2 * e, [1,2,3])
>>> s
6
>>> l
[2, 4, 6]
>>>

Dan Shappir - Re: Python 2.3 Release Schedule  blueArrow
10/15/2002; 10:54:02 AM (reads: 1260, responses: 1)
Python's generators are neat and all, but they're really just saving you the work of writing a class which saves some state in between calls.

I don't remember if I've mentioned it on LtU before, but I don't really like Python's generators. I don't remember who is was that said "it's not so much the goto as the comefrom". The traditional problem with goto is not knowing where you are going but rather how you got there.

To me, the yield statement seems to exasperate this problem. Think about it this way: C/C++ and its ilk where often lambasted for allowing multiple function exit points. It smacked too much of goto. With yield not only can you have multiple exit point, you can now have multiple entry points! So now you have the ComeFrom problem thrown at you from both directions.

It is my opinion that you should avoid complex generators and more than a single yield per generator. OTOH applying this rule thoroughly makes generators pretty much useless.

I think itertools could have been developed at any time (from Python 1.52 on, say) to work with Python's older pre-iterators: sequences.

Correct me if I'm wrong but sequences aren't lazy evaluated. This means that any serious application risks exhausting memory and severe performance penalties. This is why I added effective.

My closure() function took a function as input, and returned a new function with the same code, but with its module scope set to a new dictionary which had the locals of the enclosing function plus the globals of the enclosing function - instant closure!

Very nice. One of my pet peeves about ECMAScript is that you can't use an object as a scope nor reference a scope as an object (you can actually do the first to an extent using the deprecated with keyword). They are both, after all, implemented as directories. Still the limitation of not being able to update to actual module bindings is pretty harsh.

Bryn Keller - Re: Python 2.3 Release Schedule  blueArrow
10/15/2002; 11:31:01 AM (reads: 1287, responses: 0)
To me, the yield statement seems to exasperate this problem. Think about it this way: C/C++ and its ilk where often lambasted for allowing multiple function exit points. It smacked too much of goto. With yield not only can you have multiple exit point, you can now have multiple entry points! So now you have the ComeFrom problem thrown at you from both directions.

Makes sense. I haven't really done enough with generators to decide whether they're truly useful or just feature creep. I was always puzzled that generators made it in to Python. I think it was originally intended to support coroutines.

Correct me if I'm wrong but sequences aren't lazy evaluated. This means that any serious application risks exhausting memory and severe performance penalties. This is why I added effective.

You're quite right, but solving this problem doesn't require language changes - you just need a library that supports lazy sequences, like my lazy.py. :-) Iterators are nice in that they're standardized so everybody will use them, but that's just convention.