On 17 Apr 2005 21:48:47 -0700, "Kay Schluehr" <[EMAIL PROTECTED]> wrote: <snip> >> > >> I like this. But how would you put "where args:" and "where kw:" if >you needed both? >> also, is it looking back to see the '*' or '**' to do (::x=1).values >vs. (::x=1) >> and how about (::x=1).keys() or (::x=1).items() ? And what if you >wanted to pass >> (::x=1) as a dict object without ** expansion into a keyword dict? >> >> Maybe we need asterisks on both ends. e.g., >> >> foo(dct, values, *args, **kw): >> where **dct: >> x=1 >> where *values: >> x=2 >> where *args: >> x=3 >> where **kw: >> x=4 > >Yes... Why not?
On second thought, "where **x:" might as well be "where x:" since ** is a good default, but I think "where x:" looks too much like and ordinary suite will follow, rather than capturing the bindings created by the suite and binding that dict to x temporarily. I would rather see "where x::" to indicate that, which also ties in consistently with my syntax for for thunks as suite expressions, in that that now gives named def-like statement versions to all the anonymous versions, when you include this <name>::<suite> along with <name>(<thunkarglist>):<thunksuite> and <name> def(<defarglist>):<anonymous_def_suite> Of course that last is equivalent to an ordinary def, and I can't see using it, since a def will do everywhere except immediately following where, and the assignment form is clearer there, e.g.: foo(123) where foo=def(x): print x as a way to define a transient function and call it so with that in mind, and I just realized we can do away with * specifiers if we move that job to where the dict of bindings is used: foo(dct, values.values(), *args.values(), **kw): #XXX ':' used as function call trailer not good where dct:: # get suite as dict in all cases x=1 where values:: x=2 where args:: x=3 where kw:: x=4 Now using the same syntax to define temporarily named thunks for the arg list: thunk_accepter(tk1, tk2, [1,2], **kw) where: # now where: can introduce an ordinary where suite tk1(i): print i tk2(j): rejectlist.append(j) kw:: x = 1 y = 2 This would be equivalent to thunk_accepter(tk1, tk2, [1,2], **kw) where: tk1 = (i): print i tk2 = (j): rejectlist.append(j) kw = :: x = 1 y = 2 Which might look more "mainstream", and be ok for multiple values, but for a single thunk, which is probably the most frequent use case, a statement should be able to end in "where <single assignment or name binder>:" e.g., foo(x) where x=1 # minimal silly or named thunk definition syntax, which binds the name and uses a suite, e.g., safe_open(tk, filepath, filemode) where tk(f): for line in f: print line[:40] would be nice and concise. And it looks pretty mainstream, in that tk(f) looks just like the thunk call that safe_open will do to run the suite in the local namespace. Might even look good to Brian? ;-) But note that "where tk(f):<suite>" is really equivalent to the assignment form "where tk = (f):<suite>" much like def foo(): return 'hi' is equivalent to foo = lambda: 'hi' (and my thunk definition syntax derives from def foo(<arglist>):<suite> minus "def foo" ;-) > >> >> But that still doesn't give you, e.g., >> >> foo(keys) where: >> keys=sorted((:: >> from interesting.module import * >> ).keys()) > >This particular statement won't work anyway inside a where-clause >because >"from *" must be called from module level. You would have to import >interesting.module before: > > import interesting.module > foo(keys) where: > keys = sorted(interesting.module.__dict__).keys() > >But it wasn't ever intended to put arbitrary statements in a kw-suite, >right? Sure, as arbitrary as inside a function. Import * was a bad example. I never use that, so I shouldn't have used it in an example, even though on my system it does it, grudgingly: >>> def foo(): ... from math import * ... return vars().keys() ... <stdin>:1: SyntaxWarning: import * only allowed at module level >>> foo() ['pow', 'cosh', 'ldexp', 'hypot', 'tan', 'asin', 'log', 'fabs', 'floor', 'sqrt', 'frexp', 'degre es', 'pi', 'log10', 'sin', 'modf', 'atan', 'ceil', 'sinh', 'cos', 'e', 'tanh', 'radians', 'atan2 ', 'fmod', 'exp', 'acos'] >>> I should have put a safe import inside, using your example foo(keys) where: import interesting.module keys = sorted(interesting.module.__dict__).keys() If you import it outside of that scope, you will have 'interesting' bound outside. I'm not saying go wild and do weird things, I'm just saying don't impose arbitrary restrictions on adults. These explorations are just to illustrate possibilities, not to advocate them all as good conventional use. > >> I like clean sugar, but I still want to be able to >> get at the general primitives to compose them in ways >> that can't be anticipated until a use case comes up. >> And then if the primitives are inaccessible, one is >> out of luck or doomed to workaround hacking ;-) > >You can always consider "where" as function of a statement. The only >restriction You have to make is to bind "where" to a function-call i.e. >regard each function as a function object with a where() method. Um, I think that's too narrow for where. Consider foo = f1; bar=f2; x=k1; y=k2 foo(x)*bar(y)[3].attr now should foo(x)*bar(y)[3].attr where: foo = f1; bar=f2; x=k1; y=k2 act any different? How do you spell this as a where bound to a function call? > > >f(*args,**kw ).where( <specifier>, > (<assignment-statement>| > <function-definition>| > <class-definition>)* > ) > >But that is not a loss of generality because a free (:: x=1 ) can be >mapped onto > > dict(**kw).where(**kw, x=1) > >and that is > > dict(**kw) where **kw: > x=1 so for foo(*args) where: args = dict(**kw).keys() where **kw: x=1 but it's much easier (now with explorations and ideas above ;-) to write foo(*args.values()) where args:: x=1 > >I don't see any case where this translation fails. Only if it comes to >functional composition like > > f(g(...(h(:: x=1)...)) > >it may be awkward to expand this into a nested where clauses. You might >probably define the argument not in a suite ;) There are probably some things that won't look reasonable no matter what ;-) But to summarize, I think we should try to write a real grammar for all this, and show how it would fit in with the real python grammar. I think I should make a separate post for this ;-) see grammar for where/letting/with and suite expressions (thunks etc) Regards, Bengt Richter -- http://mail.python.org/mailman/listinfo/python-list