MathGroup Archive 2010

[Date Index] [Thread Index] [Author Index]

Search the Archive

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