Group Abstract Group Abstract

Message Boards Message Boards

0
|
4K Views
|
9 Replies
|
6 Total Likes
View groups...
Share
Share this post:

Recommended method to define local symbol names in nested Module

Posted 2 years ago

I noticed the following example here:

Module[{x = 1},
 Print[HoldForm@x, " = ", x];
  Module[{x = 2},
   Print[HoldForm@x, " = ", x];
    Module[{x = 3},
     Print[HoldForm@x, " = ", x]];
   Print[HoldForm@x, " = ", x]
  ];
 Print[HoldForm@x, " = ", x]
]

I wonder what's the recommended method to define local symbol names in nested Module. Should I reuse the same variable name as shown above, or should I use different variable names?

Regards,
Zhao

POSTED BY: Hongyi Zhao
9 Replies
Posted 2 years ago

Thank you, Hans. The following is a relevant example that I noticed here:

makeList[sep_String]:=Block[
{counter=0, makeItem},
makeItem[item_String]:=ToString[++counter]<>sep<>item;
makeItem /@ {"first", "second", "third"}
]
Scan[Print, makeList[". "]]
makeList[". "]
POSTED BY: Hongyi Zhao
Posted 2 years ago
myMakeList[sep_String, list : {___String}] := StringRiffle[Transpose[{Range[Length@list], list}], "\n", sep];
    myMakeList[". ", {"first", "second", "third"}]

Output:

1. first 2. second 3. third

Commentary

That Rosetta Code question was posed thus:

Write a program consisting of two nested functions that prints the following text...

That presupposes a particular form for the solution, a form which is completely unnecessary in Mathematica. Even the "prints" is suspicious.

The outer function (called MakeList or equivalent) is responsible for creating the list as a whole and is given the separator ". " as argument.

Wait, we don't even pass in the list to be numbered? That's just very brittle programming.

It also defines a counter variable to keep track of the item number. This demonstrates how the inner function can influence the variables in the outer function.

But this presupposes an entire programming paradigm! And it's a paradigm that does not reflect the strengths and core idioms of Mathematica.

The premise/motivation was given thus:

In many languages, functions can be nested, resulting in outer functions and inner functions.

I'd take issue with "functions" here. Sure, procedures/subroutines/blocks can be nested, but the main composition strategy with functions is function composition. My solution above uses function composition to accomplish the task. Deconstructing such a compositional pattern into a sequential one with explicit state management is just a bonkers thing to do in Mathematica. If this is one's preferred style, then that's great. It's absolutely fabulous. You will be much more comfortable with C and the whole family of languages that derive from it.

"Well," you say, "they just want to see how different constructs appear in different languages; the actual problem isn't relevant." No, they've biased the solution to such an extent that this is equivalent to asking, "how do you write C-style code in Mathematica?". To me, that's just not an interesting question.

You don't go to Disneyland to look at paintings. Can you find paintings in Disneyland? Sure, lots of them. But if you start critiquing the paintings in the Haunted Mansion, you're missing the point.

POSTED BY: Eric Rimbey
Posted 2 years ago

An example:

checkBasis[bas_?MatrixQ, pgelm_List] :=Module[
  {b,f},
  f[bb_,elm_]:=Module[
    {G1,G2},
    G1=ConjugateTranspose[bb] . bb//ComplexExpand;
    G2=(ConjugateTranspose[#] . G1 . #//ComplexExpand)&/@elm//Union;
    Length[G2]==1&&(G2[[1]]===G1)//FullSimplify
  ];
  Which[
    b=bas;f[b,pgelm],{1,b},
    b=Inverse[bas];f[b,pgelm],{2,b},
    b=ConjugateTranspose[bas]//ComplexExpand;f[b,pgelm],{3,b},
    b=ConjugateTranspose[bas]//ComplexExpand//Inverse;f[b,pgelm],{4,b}
  ]
]
POSTED BY: Hans Milton
Posted 2 years ago

I suspect that what the OP is planning to do is to rewrite each duplicate code block as a Module (within the main module).

Yes. This is exactly what I want to achieve.

But I don't know why Module would be the construct of choice in any of this.

So what is the preferred method?

POSTED BY: Hongyi Zhao
Posted 2 years ago

Functions. When you have duplicate code, you might consider replacing the duplicate code to calls to a procedure/method/function. In Mathematica, it's typical to think in terms of functions as implemented with DownValues.

Okay, philosophical rambling...

In most languages, the modularizing construct is something like a subroutine (the vocabulary here is all over the place, so don't get hung up on "subroutine"--call it whatever you want). It's a block of code in which you can set up and manage a temporary state/environment using local variables.

When people who are very familiar and comfortable with that pattern move to Mathematica (and the same applies to any of the more "functional" or Lisp-ish languages), they go looking for that kind of modularizing construct, and they eventually find Module. From that point on, you see "function" definitions based on Module. This becomes a habit, and other Mathematica idioms lie on the shelf, gathering dust.

But anyway, if you're just certain that what you want is nested Modules, then go for it. But I have no suggestions to offer you. Well, that's not true. I suggest that you just don't do this. In short, to me, your original question sounds like asking a bunch of vegetarians if they have any good tips for grilling a steak.

POSTED BY: Eric Rimbey
Posted 2 years ago

My first question is "why do you want to do that?"

I've defined the following function and I want to simplify it a bit further:

checkBasis[bas_?MatrixQ, pgelm_List] :=
    Module[{b, elm, G1, G2},
        elm = pgelm;
        Which[(*
 R bas = bas repR, aka,
 bas . # . Inverse[bas] & /@ pgens
 *)
            b = bas;
                G1 = ConjugateTranspose[b] . b // ComplexExpand;
                G2 = (ConjugateTranspose[#] . G1 . # // ComplexExpand
                    )& /@ elm // Union;
                Length[G2] == 1 && (G2[[1]] === G1) // FullSimplify,
                {1, b}
            ,
 (*
 R Inverse[bas] = Inverse[bas] repR, aka,
 Inverse[bas] . # . bas & /@ pgens
 *)b = Inverse[bas];
                G1 = ConjugateTranspose[b] . b // ComplexExpand;
                G2 = (ConjugateTranspose[#] . G1 . # // ComplexExpand
                    )& /@ elm // Union;
                Length[G2] == 1 && (G2[[1]] === G1) // FullSimplify,
                {2, b}
            ,
 (*
 R Tranpose[bas] = Tranpose[bas] repR, aka,
 Tranpose[bas] . # . Inverse[Tranpose[bas]] & /@ pgens
 *)b = ConjugateTranspose[bas] // ComplexExpand;
                G1 = ConjugateTranspose[b] . b // ComplexExpand;
                G2 = (ConjugateTranspose[#] . G1 . # // ComplexExpand
                    )& /@ elm // Union;
                Length[G2] == 1 && (G2[[1]] === G1) // FullSimplify,
                {3, b}
            ,
 (*
 R Inverse[Tranpose[bas]] = Inverse[Tranpose[bas]] repR, aka,
 Inverse[Tranpose[bas]] . # . Tranpose[bas] & /@ pgens
 *)b =ConjugateTranspose[bas] // ComplexExpand //Inverse;
                G1 = ConjugateTranspose[b] . b // ComplexExpand;
                G2 = (ConjugateTranspose[#] . G1 . # // ComplexExpand)& /@ elm // Union;
                Length[G2] == 1 && (G2[[1]] === G1) // FullSimplify,
                {4, b}
        ]
    ]
POSTED BY: Hongyi Zhao
Posted 2 years ago

There is no nesting of Module in your code

POSTED BY: Hans Milton
Posted 2 years ago

I suspect that what the OP is planning to do is to rewrite each duplicate code block as a Module (within the main module). But I don't know why Module would be the construct of choice in any of this.

POSTED BY: Eric Rimbey

My first question is "why do you want to do that?" I can't think of a good reason to nest modules like this.

POSTED BY: Jason Biggs
Reply to this discussion
Community posts can be styled and formatted using the Markdown syntax.
Reply Preview
Attachments
Remove
or Discard