[Python-ideas] Another way to avoid clumsy lambdas, while adding new functionality
Steven D'Aprano
steve at pearwood.info
Wed Mar 5 16:35:29 CET 2014
On Wed, Mar 05, 2014 at 12:41:10PM +0000, Carl Smith wrote:
> Just for the record, I never called them bills just because they contain a
> dollar sign! I was thinking of a short word which describes an expression
> who's evaluation changes depending on the local circumstances. Like a legal
> bill, not a dollar bill.
Hmmm. Well, I don't really get the connection between legal bills and
delayed evaluation, and I still really dislike the name.
> The name macro doesn't really work, as it's only an expression, it's not a
> code block.
There is nothing about macros that *require* them to accept a full block
of code. In fact, there are multiple different meanings for macro,
although they are all related they do have significant differences:
http://en.wikipedia.org/wiki/Macro_%28computer_science%29
Macros in C are not the same kind of thing as macros in Lisp.
> ---
>
> The idea was never to start passing complex expressions around the place.
What you consider a complex expression somebody else may consider a
simple expression. Unless you want to demand some arbitrary hard limit
on complexity (and how do you measure complexity?) this "bill" system
would have to allow the exact same types of expressions that are legal
elsewhere in Python.
[...]
> What the hell is a thunk anyway? It's a horrible name.
Wikipedia is your friend:
http://en.wikipedia.org/wiki/Thunk
Also, more here: http://c2.com/cgi/wiki?CallByName
The meaning of thunk I'm referring to comes from the call-by-name
argument passing model. Suppose we pass an expression to a function:
function(arg=x-1)
and the body of the function looks like this:
if arg > 1:
y = arg + 1
else:
y = arg - 1
return y*arg
In the "call-by-name" model, the function body executes like this:
if (x+1) > 1:
y = (x+1) + 1
else:
y = (x+1) - 1
return y*(x+1)
which not only duplicates the "x+1" part four times, but may require
evaluating it three times. To avoid this wasteful duplication, the
compiler creates a special thunk value, which is something like a
function with no arguments:
def thunk():
if cache is None:
cache = x-1
return cache
(This should be considered pseudo-code, not the exact way Algol or
Haskell work -- real thunks also allow you to assign a value back to the
"name". Also, technically the presence of a cache makes it call-by-need
rather than call-by-name).
The body of the function then becomes:
if thunk() > 1:
y = thunk() + 1
else:
y = thunk() - 1
return y*thunk()
So as you can see, what I've been calling a thunk is not precisely like
Algol thunks. One thing which is missing is the dynamic scoping: in the
thunk evaluation, the x comes from the caller's scope. But the delayed
evaluation part is quite similar, enough that I think the name may be
appropriate. Another name for this might be a "promise", as in the
promise to execute a computation later.
--
Steven
More information about the Python-ideas
mailing list