Mike Meyer wrote:
Personally, I'd love a language feature that let you create a function
that didn't evaluate arguments until they were actually used - lazy
evaluation. That lets you write the C ?: operator as a function, for
a start.

The basic idea is to just specify that those arguments must be zero-argument callables, and only call them if you actually need them.


The rest of this message is something that just occured to me that could make that style 'prettier' (if lambda looks as ugly in function calls to you as it does to me). It's completely untested, though :)

First, some utility functions to convert values and functions with arguments to a lazily evaluable function:

def lazy(x, *args, **kwds):
  """Executes x(*args, **kwds) when called"""
  if args or kwds:
    return lambda : x(*args, **kwds)
  else:
    return x # No arguments, so x must be callable by itself

def lazyval(x):
  """Allows passing a normal value as a deferred argument"""
  return lambda : x

def lazycall(x, *args, **kwds):
  """Executes x(*args, **kwds)() when called"""
  return lambda : x(*args, **kwds)()


For literals, their constructor provides a zero-argument callable equivalent:

[] -> list
(,) -> tuple
{} -> dict
0 -> int
"" -> str
0L -> long

And the operator module provides a way to delay most operations:

import operator
lazy(operator.mul, x, y) # Delayed x * y
lazy(operator.itemgetter(i), x) # Delayed x[i]
lazy(operator.attrgetter("a"), x) # Delayed x.a
lazycall(lazy(operator.attrgetter("a"), x)) # Delayed x.a()

(That last example is why I added lazycall() to the utility functions)

Then you can write a function called 'select':

def select(selector, *args, **kwds):
  if kwds:
    return kwds[selector]()
  else:
    return args[selector]()

And one called 'either' (since 'if' is taken and using 'select' would get the true case and the false case back to front):

def either(pred, true_case, false_case):
  if pred:
    return true_case()
  else:
    return false_case()

And use them as follows:

  select(selector, list, lazyval(mylist), lazy(eval, expr, globals(), locals()))
  select(selector, c1 = list, c2 = lazyval(mylist), c3 = lazy(myfunc, a, b, c))
  either(condition, guarded_operation, lazyval(default_case))

Huh. I think I like the idea of lazy() much better than I like the current PEP 312. There must be something wrong with this idea that I'm missing. . .

Cheers,
Nick.

--
Nick Coghlan   |   [EMAIL PROTECTED]   |   Brisbane, Australia
---------------------------------------------------------------
            http://boredomandlaziness.skystorm.net
--
http://mail.python.org/mailman/listinfo/python-list

Reply via email to