# Same code behaves differently as a pure function and a function, and insider another function

I have a rule-transformer that takes a list of rules (and a list generator = {σ[z], σ[-1], σ[1]})

algebra = {σ[z] ** σ[1] :> σ[1],
σ[z] ** σ[-1] :> -σ[-1],
σ[1] ** σ[z] :> -σ[1],
σ[-1] ** σ[z] :> σ[-1],
σ[1] ** σ[1] -> 0,
σ[-1] ** σ[-1] -> 0,
σ[z] ** σ[z] -> Id,
σ[1] ** σ[-1] -> 1/2 (Id + σ[z]),
σ[-1] ** σ[1] -> 1/2 (Id - σ[z])
}



and turn it into

{σ[z][n_] ** σ[1][n_] :> σ[1][n],
σ[z][n_] ** σ[-1][n_] :> -σ[-1][n],
σ[1][n_] ** σ[z][n_] :> -σ[1][n],
σ[-1][n_] ** σ[z][n_] :> σ[-1][n],
σ[1][n_]^2 :> 0,
σ[-1][n_]^2 :> 0,
σ[z][n_]^2 :> 1,
σ[1][n_] ** σ[-1][n_] :> 1/2 (1 + σ[z][n]),
σ[-1][n_] ** σ[1][n_] :> 1/2 (1 - σ[z][n])}


Transformer =
Table[(#[[i]][[1]] /. {$$g_ :>$$g[n_] /; MemberQ[generators, $g]}) :> Evaluate[(#[[i]][[ 2]] /. {gg_ :> gg[n] /; MemberQ[generators, gg]})], {i, Length[#]}] &;  I can call Transformer[algebra] to generate the desired list. However, if I define Transformer by Transformer[algebra_] := Table[(algebra[[i]][[ 1]] /. {$g_ :> $g[n_] /; MemberQ[generators,$g]}) :>
Evaluate[(algebra[[i]][[
2]] /. {gg_ :> gg[n] /; MemberQ[generators, gg]})], {i,
Length[algebra]}]


calling Transformer[algebra] gives some weird output

{σ[z] ** σ[1] :> σ[1][
n$], σ[z] ** σ[-1] :> -σ[-1][n$], σ[
1] ** σ[z] :> -σ[1][n$], σ[-1] ** σ[ z] :> σ[-1][n$], σ[1]^2 :> 0, σ[-1]^2 :>
0, σ[z]^2 :> 1, σ[1] ** σ[-1] :>
1/2 (1 + σ[z][n$]), σ[-1] ** σ[1] :> 1/2 (1 - σ[z][n$])}


Similarly, if I put the pure function definition of Transformer inside the definition of some other bigger function, the same weird output will generate.

I wonder why the function environment causes such a big difference?

• Your "weird output" case is because you defined Transformer to take an argument and produce a Function. You didn't actually include the full output, but if you look carefully at your actual output, you'll see that it's a Function expression (you can either see the & at the end or you can look at FullForm and see a Function head. Just remove the & from the end of your definition. Nov 12, 2023 at 15:17
• @lericr you are right. I removed the & and now there is a new output which is still not desirable. Am I using the Evaluate incorrectly? Nov 13, 2023 at 0:42

That's due to the renaming mechanism of nested scopings.

When evaluating Transformer2[algebra_] := , the local variable algebra needs to be evaluated in the right side, and there appears a double scoping involving local variables algebra, $g, ..., then the rule {$g_ :> $g[n_] /; MemberQ[generators,$g]})


is automatically renamed as

{$g$_ :> $g[n$_] /; MemberQ[generators, $g]}  Instead, if you define Transformer22[algebra_] := Table[ (rule[[1]] /. {$g_ :> $g[n_] /; MemberQ[generators,$g]}):>
Evaluate[(rule[[2]] /. {gg_ :> gg[n] /; MemberQ[generators, gg]})],
{rule,algebra}
]


or just the pure function you have given, the local variable algebra will be replaced by its value and there is no nested scoping during evaluation.

This doesn't really seem to have to do with Function versus SetDelayed, so it might warrant a separate question. Rather then debug the provided code, I'd suggest a different approach.

Whenever you have a construct like Table[..., {i,Length[something]}], you would probably be better off with some sort of Map. But, since what you're really doing is ReplaceAll, you don't need to iterate explicitly at all. But again, you do want a slightly different replacement to the left hand sides than to the right hand sides. But SubsetMap gives us a nifty way to handle such situations. So, I'd proceed like this:

(* create replacement rules *)
lhsRules = Thread[generators -> (Construct[#, n_] & /@ generators)];
rhsRules = Thread[generators -> (Construct[#, n] & /@ generators)];

result =
RuleDelayed @@@
(SubsetMap[
ReplaceAll[rhsRules],
SubsetMap[ReplaceAll[lhsRules], Level[#, 1] & /@ algebra, {All, 1}],
{All, 2}] /. x_ ** x_ :> x^2)


Now, you use 1 is some places and Id in others, so you'll need to sort that out.

Of course, you can put this into a definition:

Transformer[algebra_] := ...

• Thanks for the suggestions; I haven't used SubsetMap before. I'll implement something like this in the future code. Nov 14, 2023 at 2:38