|
[Date Index]
[Thread Index]
[Author Index]
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
>
- References:
- looping
- From: glenn kuhaneck <mcguyver128@yahoo.com>
Prev by Date:
Re: Re: looping
Next by Date:
ElementData[] Problems
Previous by thread:
Re: Re: looping
Next by thread:
Re: Re: Re: looping
|