[Python-ideas] Multi-statement anonymous functions

musicdenotation at gmail.com musicdenotation at gmail.com
Mon Jan 13 15:06:03 CET 2014


> On Jan 13, 2014, at 18:16, Andrew Barnert <abarnert at yahoo.com> wrote:
> 
>> On Jan 13, 2014, at 3:06, musicdenotation at gmail.com wrote:
>> 
>> Mutable namespaces and modules are just workarounds and cannot be substituted for local namespaces.
> 
> Sure, in the exact same way that mutable file objects are just workarounds and cannot be substituted for an I/O monad.
> 
> If you don't think being able to write "a=3" and modify the current (module/class/local) scope is helpful, I think you may be using the wrong language.
> 
>> ---Original message---
>> From: Andrew Barnert
>> Sent: Mon, 13 Jan 2014 00:21:07 -0800
>> To: <|musicdenotation at gmail.com|><|python-ideas at python.org|>
>> Subject: Re: [Python-ideas] Multi-statement anonymous functions
>> 
>> 
>> From: "musicdenotation at gmail.com" <musicdenotation at gmail.com>
>> 
>> Sent: Sunday, January 12, 2014 10:48 PM
>> 
>> 
>>> Subject: [Python-ideas] Multi-statement anonymous functions
>>> 
>>> Proposed syntaxes:
>>>> let function(*args,**kwargs):
>>>>     ...body...
>>>> function2(...args...):
>>>>     ...body...
>>>> in:
>>>>     [statements]
>>> 
>>>> do:
>>>>     [statements]
>>>> where [function declarations in the same form as above]
>>> 
>>> Inspired by Haskell and Julia.
>>> 
>>> This has the advantage that declared functions aren't binded to names 
>>> outside their context.
>> 
>> 
>> I think there's something interesting here, but I'm not seeing it. What's the actual use case for this?
>> 
>> If you haven't read PEP 403 and PEP 3150, you should; they both offer similar (but not identical) features in a way that seems more readable (both more compact, and "fronting" the most important part of the construct):
>> 
>> 
>>    @in statement that uses function1
>>    def function1(*args, **kwargs):
>>        body
>> 
>>    statement that uses function1 and var1 given:
>>        def function1(*args, **kwargs):
>>            body
>>        var1 = value
>> 
>> Meanwhile, my first question for your syntax is: Why limit it to function definitions? It's worth noting that a Haskell let statement creates local bindings for any values you want; it's not restricted to functions. And that restriction is the only thing that forces the awkward block structure (which would need to be parsed differently than existing Python structures, both by the compiler and by human readers). Why not just a let statement that lets you execute _any_ statements in a local scope, then use that scope:
>> 
>>    let:
>> 
>>        def function1(*args, **kwargs):
>>            body
>>        var = value
>>        any other statement you want
>>    in:
>>        statements
>> 
>> … or, for that matter, just a local-scope statement:
>> 
>>    local:
>>        def function1(*args, **kwargs):
>>            body
>>        var = value
>>        any other statement you want
>>        statements that use those definitions
>> 
>> 
>> This has an advantage over Nick Coghlan's two proposals in that you get to run a full suite with the local scope, instead of just a single statement. (His fronting of the statement makes that restriction necessary; yours doesn't.)
>> 
>> But I'm wondering why you need a local scope. 
>> 
>> The let statement is necessary in Haskell because namespaces, like everything else, are immutable, and there are no real assignments; if you want to bind another variable, you have to create a new scope with that binding on top of the existing one. In Python, if you want to bind another variable, you just use an assignment/def/class/etc. And if you're worried about the name being accessible from outside of the namespace (e.g., if someone does a "from foo import *" on you), there are already idiomatic ways to deal with that: prefix the name with _, or give the module an __all__. Or, again: Python namespaces are mutable, so you can just del a binding after you're done with it if you really need to.
>> 
>> Coming at it from a different angle, JavaScript—which has mutable namespaces very much like Python—needs local scopes pretty frequently. But that's only because it has no modules, so everything is in one giant global namespace, which makes it hard to avoid conflicts, figure out where things are defined, etc. So that doesn't seem to apply to Python either.
>> 
>> Also, in most cases where you _do_ need a local scope, just defining and calling a function works just fine. That's what people do in Python when they need a local binding for micro-optimization purposes. And the same idiom is used all over the place in JavaScript (which, again, needs local scopes much more often than Python). Is there a use case where that isn't appropriate?
No, an I/O monad is a workaround for free side effects. What I want is a canonical, obvious, natural solution to a problem, not a workaround.


More information about the Python-ideas mailing list