args (was Re: Lambda as declarative idiom (was RE: what is lambda used for in real code?))

Bengt Richter bokr at oz.net
Fri Jan 7 16:33:36 EST 2005


On Tue, 04 Jan 2005 14:11:51 -0800, Michael Spencer <mahs at telcopartners.com> wrote:
[Hm, this didn't go out for some reason. I'll just send it now.]

>Roman Suzi wrote:
>
>> Maybe this is too outlandish, but I see lambdas as a "quote" mechanism,
>> which presents a possibility to postpone (precisely control, delegate)
>> evaluation. That is, an ovehead for lambda must be much lower but at the
>> same time visible to the programmer:
>> 
>>  d = a + (lambda x, y: x+ y)(3, 4)
>[...]
>
>I believe that this "possibility to postpone" divides into two related but 
>separate concepts: controlling the moment of evaluation, and assembling the 
>arguments required at that moment.  They are both species of 'eval', but 
>managing arguments is more specialized, because it includes possibly renaming 
>parameters, assigning default values, processing positional and keyword 
>arguments, and, perhaps in the future dealing with argument types.
>
I imagine that you should be able to identify bytecode substrings in current code
that would have to be part of an implementation of what you are proposing.
But ISTM mabe there's three concepts: 1) defining the formal parameter list,
which is like a template for unpacking and binding an actual arglist produced by
2) the source code for a call of some named function with expression for actual
arguments, and 3) the run time excution of the code compiled from (2).

AFAICS, currently there is no linkage between the called function and the calling code
except that the first thing put on the stack is just the result of an expression that
_should_ put a reference to a compatible callable on the stack. What follows is a sequence
of argument expressions which stack the arg values, and then finally the byte code is executed
to make one of several kinds of specialized function calls to use the stack contents.
At that point the 'callable' could be None, or another function with the wrong signature.

What I see as the deferred-args-evaluation part is the code between pushing the callable
reference and making the specialized call. But that can't be what your args function is,
since UIAM the 'arguments' to that are not run time calling arguments, but a particular
formal parameter signature. That's a guide for unpacking and binding a call's arguments
at an associated function's entry, to create a _part_ of the local bindings, which has
nothing to do with deferring the evaluation of the call args.


>Meanwhile, GvR wrote (about defining Interfaces in the context of Optional 
>Static Type Checking)
>> Method declarations can be inspected to find out their signature. I propose a
>> __signature__ attribute (also for methods defined in classes!) which might be an
>> object whose attributes make the signature easily inspectable. This might take 
>> the form of a list of argument declaration objects giving the name, type and default
>> (if any) for each argument, and a separate argument for the return type. For 
>> signatures that include *args and/or **kwds, the type of the additional arguments 
>> should also be given (so you can write for example a varargs method whose arguments
>> are all strings).
>
>GvR's method.__signature__ object might be related to the args object I proposed 
>  as part of the syntax for anonymous functions without 'lambda'. i.e.,
>
>     args(a,*b,**kw) --> an object that specifies but does not evaluate its 
>parameters until it is supplied to a callable, possibly with calling parameters
This is the part I don't understand. To me, that expression doesn't have anything to
do with evaluating parameters, it has to do with unpacking a particular call's parameters
after they have been evaluated.  If it could "evaluate ist parameters" it would have
to have code in it to do that, but the code for evaluation of parameters is generated
from the translation of the calling code. And there might be dozens of lines calling
the same function. I.e., args(a,*b,**kw) specifies formal parameter names and structural
information for dealing with callers' post-evaluation actual args.

The only way it could have the ability to control evaluation of args is if it had a reference
to a deferred-arg-eval byte code snippet. IOw, maybe the function should be called argsig instead
of args and args could deal with deferred actual arg evaluation. Then the tuple
    argsig(x, y), args(1, 2)
could conceptually be like a bound method for deferred evaluation or args _and_ binding to
names in some namespace like a function's local namespace, but maybe not necessarily. Maybe
it could be applied to other namspaces as well. ... just musing ;-)

>
>This object would contain the default values, and could contain type 
>annotations, explicit, or inferred, as well as more complex assertions used in 
>several contexts.
But it has to be clear that until a particular calling-args list (deferred or not) is
selected by being the "current one" of possibly many, the object doesn't have arg values
to mess with.
>
>* Current function syntax:
>	def func(a,*b,**c) : pass
>
>	creates func with func.__signature__ = args(a,*b,**c)
>	and when func is called, the args are evaluated using a mechanism in
>	args.__call__
>	so, roughly, eval(func.__signature__) --> func.locals
Again, see above for argsig vs argeval. Or what am I missing?
>
>
>  * Anonymous functions
>	Syntax alternatives at http://www.python.org/moin/AlternateLambdaSyntax
>	e.g., (f(a) + o(b) - o(c) for args(a, b, c))
>	
>	args would evaluated with the calling parameters and made available in 			the 
>local scope defined by ()
>	
>  * A stricter alternative to keyword arguments:
>  	argspec = args(arg1, arg2, arg3)
>	def func(**argspec): pass
>	
>	is equivalent to def func(arg1, arg2, arg3): pass
>
>	
>	args["arg1"]
>	
>	(i.e., only args defined in argspec are accepted)
>
>  * Useful infrastructure for user-supplied type-based dispatch/lightweight 
>multimethods:
>	
>	argspec = args([(a:int, b:int),(a:str,b:str)])
>	
>	then a framework can provide a custom args.__call__ method that does
>	conformance-checking, adaptation or whatever
>

BTW, if argseval(arg1, etc) pushes arg1 and etc when "called"
sort of like (*lambda arg,etc:arg,etc) without packing/unpacking
then maybe they could be added, so argseval(a,b)+argseval(c) == argseval(a,b,c).
Don't know what that would be good for. Maybe in currying or such?

Regards,
Bengt Richter



More information about the Python-list mailing list