Re: Re: looping
- To: mathgroup at smc.vnet.net
- Subject: [mg106861] Re: [mg106766] Re: [mg106704] looping
- From: DrMajorBob <btreat1 at austin.rr.com>
- Date: Mon, 25 Jan 2010 05:07:38 -0500 (EST)
- References: <201001210955.EAA16523@smc.vnet.net>
- Reply-to: drmajorbob at yahoo.com
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
- References:
- looping
- From: glenn kuhaneck <mcguyver128@yahoo.com>
- looping