Re: Re: looping
- To: mathgroup at smc.vnet.net
- Subject: [mg106866] Re: [mg106766] Re: [mg106704] looping
- From: Leonid Shifrin <lshifr at gmail.com>
- Date: Mon, 25 Jan 2010 05:08:35 -0500 (EST)
- References: <201001210955.EAA16523@smc.vnet.net>
Bobby, I had no doubt you'd like this one. I really hope that this feature will stay in later versions. Besides, changes to this seem unlikely because this is a fundamental mechanism behind scoping in Module, and it has been this way for a very long time (I don't know since which version but I wouldn't be surprised if it was there already in version 1). Regards, Leonid On Sun, Jan 24, 2010 at 10:51 AM, DrMajorBob <btreat1 at austin.rr.com> wrote: > Huh! That's an amazing little secret trick you have, there! > > I wonder, though, if it could go away in a new version. > > Bobby > > > On Sun, 24 Jan 2010 04:11:07 -0600, Leonid Shifrin <lshifr at gmail.com> > wrote: > > Bobby, >> >> this is one of the nice (IMO) features of local variables in Module. By >> default, they have the attribute Temporary, which means that they are >> destroyed once the execution exits Module. However, if some global symbols >> refer to them (like the functions you've mentioned), they are not >> destroyed, >> but kept in a symbol table. I use this trick all the time - this allows >> for >> example to share local variables (and functions) between several >> functions, >> which enables us to implement something similar to classes in OOP (If I >> remember corerctly, this idea has been fully exploited by Roman Maeder in >> his implementation of OOP in Mathematica - classes.m package). >> >> Have a look at my post in this thread, if you will >> >> >> http://groups.google.com/group/comp.soft-sys.math.mathematica/browse_thread/thread/ec4958c35f99758d/ >> >> there I implement the <pair> data type using this idea. In this thread: >> >> >> http://groups.google.com/group/comp.soft-sys.math.mathematica/browse_thread/thread/4d566f1993c252c8/ >> >> I used this trick to implement traversals of nested directory structure >> with >> possible directory skips which can be set at run-time based on a skip >> function provided by the user. >> >> One of the many other ways to use this which I find useful is to propagate >> exceptions of a given type without explicitly making the exception tag >> global. One particular such use I discussed in the thread: >> >> >> http://groups.google.com/group/comp.soft-sys.math.mathematica/browse_thread/thread/bc41b4a5f51fbcb8/ >> >> Generally, this is a good option when you want to make an essentially >> global variable available to a given set of functions but not to others - >> you make it like >> >> Module[{youvar}, >> >> f1[args]:=(body-referring-to-yourvar) >> >> f2[args]:=(body-referring-to-yourvar) >> >> ... >> ]; >> >> This is a cheap way to introduce namespaces without making a full-blown >> package. This allows us to use some of the nice OOP-like stuff (such as >> private variables / methods) without the need to employ a general OOP >> machinery (that is, when we just need nice encapsulation but not so much >> OO-style polymorphism / inheritance). As long as the user never uses >> variables with a dollar sign in their names (which can possibly collide >> with >> those generated by Module), this should be safe enough. >> >> One use of this is to make functions with "memory", similar to static >> local >> variables in C functions - some of the function's variables remember their >> values in between function calls. For example, the following function will >> produce the next Fibonacci number on demand, and yet it will be as fast as >> the iterative loop implementation for generation of consecutive Fibonacci >> numbers (since Module is invoked only once, when the function is defined): >> >> In[1]:= Module[{prev, prevprev, this}, >> reset[] := (prev = 1; prevprev = 1); >> reset[]; >> nextFib[] := (this = prev + prevprev; prevprev = prev; prev = this)]; >> >> >> In[2]:= >> reset[]; >> Table[nextFib[], {1000}]; // Timing >> >> Out[3]= {0.01, Null} >> >> In some cases, this can also improve performance, since some of the local >> variables in a function can be made "semi-global" by this trick which may >> eliminate the need of Module invocation in each function call, and the >> associated overhead: >> >> In[4]:= >> Clear[f, f1]; >> f[x_, y_, z_] := Module[{xl = x, yl = y, zl = z}, (xl + yl + zl)^2]; >> >> In[6]:= >> Module[{xl, yl, zl}, >> f1[x_, y_, z_] := (xl = x; yl = y; zl = z; (xl + yl + zl)^2)]; >> >> >> In[8]:= test = RandomInteger[100, {10000, 3}]; >> >> In[9]:= f @@@ test; // Timing >> >> Out[9]= {0.43, Null} >> >> In[10]:= f1 @@@ test; // Timing >> >> Out[10]= {0.15, Null} >> >> >> I generally find this technique very useful, and also I think that it has >> not been fully exploited (at least I did not fully exploit it yet). For >> example, you can do nice things when you couple it with Dynamic >> functionality, since Dynamic happens to work also on these >> Module-generated >> variables. >> >> It may however have some garbage-collection issues (I discussed this in >> the >> first of the threads I mentioned above), since once you abandon such local >> variables/functions, they will not be automatically garbage-collected by >> Mathematica and can soak up memory (I have been bitten by this a few >> times). >> Of course, this can be dealt with as well, it's just not automatic. >> >> Regards, >> Leonid >> >> >> >> >> >> >> On Sat, Jan 23, 2010 at 5:18 PM, DrMajorBob <btreat1 at austin.rr.com> >> wrote: >> >> Thanks! I've just noticed something I don't understand, however. >>> >>> How can displayPanel[] be used outside the makeScorePanel function, when >>> it >>> uses studentInfo, text, buttons, and class -- all of which are local to >>> the >>> Module?? >>> >>> Bobby >>> >>> >>> On Sat, 23 Jan 2010 14:57:25 -0600, Leonid Shifrin <lshifr at gmail.com> >>> wrote: >>> >>> Hi Bobby, >>> >>>> >>>> I agree - your modification makes it more elegant. I particularly liked >>>> your use of indexed variables and RandomChoice. >>>> >>>> Cheers, >>>> Leonid >>>> >>>> >>>> On Sat, Jan 23, 2010 at 12:48 PM, DrMajorBob <btreat1 at austin.rr.com> >>>> wrote: >>>> >>>> I'd style this a bit differently: >>>> >>>>> >>>>> Clear[makeScorePanel]; >>>>> makeScorePanel[names : {__String}] := >>>>> Module[{text, k = Length@names, name = RandomChoice@names, >>>>> studentInfo, classFlag = True, buttons, class, percent, next, >>>>> correct, questions}, >>>>> >>>>> "internal functions"; >>>>> correct[_] = 0; questions[_] = 0; >>>>> percent[name_] /; questions[name] == 0 = 0; >>>>> percent[name_] := Round[100*correct[name]/questions[name]]; >>>>> >>>>> "display elements"; >>>>> >>>>> text = "Was the answer correct?"; >>>>> next := (questions[name]++; name = RandomChoice@names); >>>>> >>>>> class := >>>>> If[classFlag, >>>>> Panel[Grid[ >>>>> Prepend[Transpose[{names, getQuestionCount[], >>>>> getCorrectCount[], getPercent[]}], {"Name", "Questions", >>>>> "# correct", "% correct"}], Spacings -> 3, >>>>> Dividers -> Center]], ""]; >>>>> buttons := >>>>> Row[{Button[" Yes ", correct[name]++; next], >>>>> Button[" No ", next], >>>>> Button[If[classFlag, "Hide Roster", "Show Roster"], >>>>> classFlag = ! classFlag]}]; >>>>> studentInfo := >>>>> Panel[ >>>>> Grid[{{"Name", name}, {"Questions", >>>>> questions@name}, {"Correct answers", >>>>> correct@name}, {"% correct", percent@name}}, >>>>> Alignment -> Left]]; >>>>> >>>>> "exported functions"; >>>>> Clear[getCorrectCount, getQuestionCount, getPercent, >>>>> displayPanel]; >>>>> getCorrectCount[] := correct /@ names; >>>>> getQuestionCount[] := questions /@ names; >>>>> getPercent[] := percent /@ names; >>>>> displayPanel[] := >>>>> >>>>> Dynamic@Panel[Column[{studentInfo, text, buttons, class}]] >>>>> ]; >>>>> makeScorePanel[{"apple", "bob", "cat", "dog", "ear", "frog", "greg", >>>>> "hippo", "i9", "joe"}] >>>>> displayPanel[] >>>>> >>>>> Bobby >>>>> >>>>> >>>>> On Sat, 23 Jan 2010 06:30:56 -0600, Leonid Shifrin <lshifr at gmail.com> >>>>> wrote: >>>>> >>>>> Hi Glenn, >>>>> >>>>> >>>>>> You don't need a loop at all, if I understand your goal correctly. >>>>>> What >>>>>> you >>>>>> need is a bit of Dynamic functionality. Hope this will get you >>>>>> started: >>>>>> >>>>>> Clear[makeScorePanel, getScores, getCalled, getPrcntp, bpanel]; >>>>>> makeScorePanel[names : {__String}] := >>>>>> Module[{text, n = RandomInteger[Length[names] - 1] + 1, studentInfo, >>>>>> classFlag = False, buttons, class, percent, next, >>>>>> score , called , prcnt}, >>>>>> Clear[getScores, getCalled, getPrcntp, bpanel]; >>>>>> score = called = prcnt = Table[0, {Length[names]}]; >>>>>> getScores[] := score; >>>>>> getCalled[] := called; >>>>>> getPrcntp[] := prcnt; >>>>>> text := "Was the answer correct?"; >>>>>> next := (called[[n]]++; n = RandomInteger[Length[names] - 1] + 1); >>>>>> class := >>>>>> If[classFlag, >>>>>> Panel[Grid[ >>>>>> Transpose[{names, score, >>>>>> IntegerPart[100*score/(called /. (0 -> 1))]/100.} >>>>>> ], >>>>>> Spacings -> 3, Dividers -> Center]], >>>>>> ""]; >>>>>> buttons := >>>>>> Row[{ >>>>>> Button[" Yes ", score[[n]]++; next], >>>>>> Button["Class", classFlag = ! classFlag], >>>>>> Button[" No ", next]}]; >>>>>> percent := >>>>>> If[called[[n]] == 0, 0, >>>>>> IntegerPart[100*score[[n]]/called[[n]]]/100.]; >>>>>> studentInfo := >>>>>> Panel[Grid[ >>>>>> {{"Name", names[[n]]}, >>>>>> {"Times called", called[[n]]}, >>>>>> {"# of correct answers", score[[n]]}, >>>>>> {"Your % ", percent}}, >>>>>> Alignment -> Left]]; >>>>>> bpanel[] := >>>>>> Dynamic@Panel[Column[{ >>>>>> studentInfo, >>>>>> text, >>>>>> buttons, >>>>>> class >>>>>> }]]]; >>>>>> >>>>>> The way to use: first call the makeScorePanel[] with your actual list >>>>>> of >>>>>> names, then call bpanel[]: >>>>>> >>>>>> makeScorePanel[{"apple", "bob", "cat", "dog", "ear", "frog", "greg", >>>>>> "hippo", "i9", "joe"}] >>>>>> >>>>>> bpanel[] >>>>>> >>>>>> You stop when you feel like it. You can also call getScores[], >>>>>> getCalled[] >>>>>> , getPrcntp[] at any time to get the current state of these variables >>>>>> (if >>>>>> you need that for further processing). >>>>>> >>>>>> Regards, >>>>>> Leonid >>>>>> >>>>>> >>>>>> >>>>>> On Thu, Jan 21, 2010 at 12:55 PM, glenn kuhaneck < >>>>>> mcguyver128 at yahoo.com >>>>>> >wrote: >>>>>> >>>>>> this code is supposed to randomly select a student from a list, keep >>>>>> >>>>>> track >>>>>>> of how many times he/she has been called, and how many answers they >>>>>>> have >>>>>>> gotten correct. >>>>>>> >>>>>>> I am having problems getting the following code to repeat on request: >>>>>>> i >>>>>>> have tried do loops, while loops, and labels none have worked. >>>>>>> please >>>>>>> help >>>>>>> >>>>>>> These are the sample lists I am using for the code below >>>>>>> name = ( { >>>>>>> {"apple"}, >>>>>>> {"bob"}, >>>>>>> {"cat"}, >>>>>>> {"dog"}, >>>>>>> {"ear"}, >>>>>>> {"frog"}, >>>>>>> {"greg"}, >>>>>>> {"hippo"}, >>>>>>> {"i9"}, >>>>>>> {"joe"} >>>>>>> }); score = ({ >>>>>>> {0}, >>>>>>> {0}, >>>>>>> {0}, >>>>>>> {0}, >>>>>>> {0}, >>>>>>> {0}, >>>>>>> {0}, >>>>>>> {0}, >>>>>>> {0}, >>>>>>> {0} >>>>>>> }); called = ({ >>>>>>> {0}, >>>>>>> {0}, >>>>>>> {0}, >>>>>>> {0}, >>>>>>> {0}, >>>>>>> {0}, >>>>>>> {0}, >>>>>>> {0}, >>>>>>> {0}, >>>>>>> {0} >>>>>>> }); prcnt = ( { >>>>>>> {0}, >>>>>>> {0}, >>>>>>> {0}, >>>>>>> {0}, >>>>>>> {0}, >>>>>>> {0}, >>>>>>> {0}, >>>>>>> {0}, >>>>>>> {0}, >>>>>>> {0} >>>>>>> } ); >>>>>>> >>>>>>> >>>>>>> >>>>>>> >>>>>>> this is the code to manipulate the lists created above >>>>>>> repeat = "yes"; >>>>>>> c = "wrong"; >>>>>>> l = Length[name]; >>>>>>> n = RandomInteger[l - 1] + 1; >>>>>>> >>>>>>> >>>>>>> Label[begin] >>>>>>> "Student #" >>>>>>> n >>>>>>> name[[n]] >>>>>>> called[[n]] += 1; >>>>>>> "# times called" >>>>>>> called >>>>>>> "Old Score" >>>>>>> score >>>>>>> Input["Was the answer correct?", Button["Yes", c = "Right"]]; >>>>>>> If[c == "Right", score[[n]] += 1]; c >>>>>>> "New Score" >>>>>>> score >>>>>>> "Your # of Correct Answers" >>>>>>> score[[n]] >>>>>>> "Your %" >>>>>>> prcnt[[n]] = score[[n]]/called[[n]] >>>>>>> "Class %" >>>>>>> prcnt >>>>>>> Input["Another ?", Button["No", repeat = "no"]]; >>>>>>> If[repeat == "yes", Goto[begin], Goto[end]]; >>>>>>> Label[end]; >>>>>>> prcnt[[n]] >>>>>>> >>>>>>> >>>>>>> >>>>>>> thank you for your assistance, >>>>>>> Mr. Glenn J. Kuhaneck >>>>>>> >>>>>>> >>>>>>> >>>>>>> >>>>>>> >>>>>> >>>>>> -- >>>>> DrMajorBob at yahoo.com >>>>> >>>>> >>>>> >>> -- >>> DrMajorBob at yahoo.com >>> >>> > > -- > DrMajorBob at yahoo.com >
- Follow-Ups:
- Re: looping
- From: Noqsi <jpd@noqsi.com>
- Re: Re: Re: looping
- From: Andrzej Kozlowski <akozlowski@gmail.com>
- Re: looping
- References:
- looping
- From: glenn kuhaneck <mcguyver128@yahoo.com>
- looping