On Sat, 16 Apr 2005 18:46:28 -0700, Brian Sabbey <[EMAIL PROTECTED]> wrote: [...] >> In that case, my version would just not have a do, instead defining the do >> suite >> as a temp executable suite, e.g., if instead >> >> >> we make an asignment in the suite, to make it clear it's not just a calling >> thing, e.g., >> >> do f(27, 28): >> x = stuff() >> >> then my version with explict name callable suite would be >> >> def f(thunk, a, b): >> # a == 27, b == 28 >> before() >> thunk() >> after() >> >> set_x(): >> x = stuff() # to make it plain it's not just a calling thing >> >> f(set_x, 27, 28) >> # x is now visible here as local binding >> >> but a suitable decorator and an anonymous callable suite (thunk defined my >> way ;-) would make this >> >> @f(27, 28) >> (): x = stuff() >> > >Hmm, but this would require decorators to behave differently than they do >now. Currently, decorators do not automatically insert the decorated >function into the argument list. They require you to define 'f' as: > >def f(a, b): > def inner(thunk): > before() > thunk() > after() > return inner > >Having to write this type of code every time I want an thunk-accepting >function that takes other arguments would be pretty annoying to me. > Yes, I agree. That's the way it is with the decorator expression. Maybe decorator syntax is not the way to pass thunks to a function ;-)
My latest thinking is in terms of suite expressions, ::<suite> being one, and actually (<arglist>):<suite> is also a suite expression, yielding a thunk. So the call to f could just be written explicitly with the expression in line: f((():x=stuff()), 27, 28) or f((): x = stuff() done = True ,27, 28) # letting the dedented ',' terminate the ():<suite> rather than parenthesizing or safe_open((f): for line in f: print f[:20] ,'datafile.txt', 'rb') That's not too bad IMO ;-) >>> >>> Thunks can also accept arguments: >>> >>> def f(thunk): >>> thunk(6,7) >>> >>> do x,y in f(): >>> # x==6, y==7 >>> stuff(x,y) >> >> IMO >> @f >> (x, y): stuff(x, y) # like def foo(x, y): stuff(x, y) >> >> is clearer, once you get used to the missing def foo format >> > >OK. I prefer a new keyword because it seems confusing to me to re-use >decorators for this purpose. But I see your point that decorators can be >used this way if one allows anonymous functions as you describe, and if >one allows decorators to handle the case in which the function being >decorated is anonymous. I tend to agree now about using decorators for this. With thunk calling parameter and extra f calling parameters, in line would look like f((x,y): # x==6, y==7 stuff(x, y) ,'other' ,'f' ,args) I guess you could make a bound method to keep the thunk dothunk_n_all = f.__get__((x, y): stuff(x,y) ,type(():pass)) and then call that with whatever other parameter you specified for f do_thunk_n_all(whatever) if that seemed useful ;-) > >>> >>> The return value can be captured >>> >> This is just a fallout of f's being an ordinary function right? >> IOW, f doesn't really know thunk is not an ordinary callable too? >> I imagine that is for the CALL_FUNCTION byte code implementation to discover? > >yes > >> >>> def f(thunk): >>> thunk() >>> return 8 >>> >>> do t=f(): >>> # t not bound yet >>> stuff() >>> >>> print t >>> ==> 8 >> That can't be done very well with a decorator, but you could pass an >> explicit named callable suite, e.g., >> >> thunk(): stuff() >> t = f(thunk) > >But not having to do it that way was most of the purpose of thunks. I forgot that ():<suite> is an expression t = f(():stuff()) # minimal version or final_status = safe_open((f): for line in f: print f[:20] ,'datafile.txt', 'rb') <snip> > >It wouldn't be a problem to use 'return' instead of 'continue' if people >so desired, but I find 'return' more confusing because a 'return' in 'for' >suites returns from the function, not from the suite. That is, having >'return' mean different things in these two pieces of code would be >confusing: > >for i in [1,2]: > return 10 > >do i in each([1,2]): > return 10 But in my syntax, each((i): return 10 ,[1,2]) Um, well, I guess one has to think about it ;-/ The thunk-accepter could pass the thunk a mutable arg to put a return value in, or even a returnvalue verse thunk? def accepter(thk, seq): acquire() for i in seq: thk(i, (retval):pass) if retval: break release() accepter((i, rvt): print i rvt(i==7) # is this legal? , xrange(10)) Hm, one thing my syntax does, I just noticed, is allow you to pass several thunks to a thunk-accepter, if desired, e.g., (parenthesizing this time, rather than ending ():<suite> with dedented comma) each( ((i): # normal thunk print i), ((j): # alternative thunk rejectlist.append(j)), [1,2]) <snip> >I see what you're getting at with decorators and anonymous functions, but >there are a couple of things that, to me, make it worth coming up with a >whole new syntax. First, I don't like how one does not get the thunk >inserted automatically into the argument list of the decorator, as I >described above. Also, I don't like how the return value of the decorator >cannot be captured (and is already used for another purpose). The fact >that decorators require one more line of code is also a little bothersome. >Decorators weren't intended to be used this way, so it seems somewhat >hacky to do so. Why not a new syntax? > Ok, I agree this does not fit decorators well. And I do agree that a nice syntax that sugars over the creation and passing of thunks makes for clean simple cases, but I would like access to the non-sugar primitives too, which for do <opt assignment> <thunk arg list> in <callable>(<arglist>): <thunk-defining suite> IIUC translates to my < opt assignment> <callable>(((<thunk arg list>): <thunk-defining-suite>),<arglist>) With possible paren dropping and white space insertion if you want to arrange things. With the primitives, I can pass multiple thunks to an accepter, and put them in specific arg positions. I also can also bind it and use it to get a side effect out of a generator expression that now has its own scope, e.g., count = 0 counter(count): count +=1 list(i for i in xrange(20) if counter() or True) Interestingly, this ought to work, right? stopper(i): if i>5: raise StopIteration list(stopper(i) or i for i in xrange(20)) All untested hadwaving, of course ;-) Regards, Bengt Richter -- http://mail.python.org/mailman/listinfo/python-list