(I'm not sure if the title of this question is appropriate, sorry!)
After defining selfApply function that resolves the mutual references contained in Association, I wrote the following code:
selfApply[x_Association] := x //. x;
u[a_] := Module[{f},
f[t_] := t^2; (f is actually intended to be non-Listable function )
selfApply@<|"x" -> 2 a, "y" -> (f /@ "x"), "z" -> "y"[[2]]|>
]
u[Range[3]]
The result I expect is
<|"x" -> {2, 4, 6}, "y" -> {4, 16, 36}, "z" -> 16|>, but the output is
Part::partd: Part specification y[[2]] is longer than depth of object.
<|"x" -> {2, 4, 6}, "y" -> {2, 4, 6}, "z" -> 4|>
with warning.
It is obvious that it stucks at the stage of evaluating f /@ "x" and "y"[[2]], so I tried to rewrite it as follows using RuleDelayed:
selfApply[x_Association] := x //. x;
u[a_] := Module[{f},
f[t_] := t^2;
selfApply@<|"x" -> 2 a, "y" :> f /@ "x", "z" :> "y"[[2]]|>
]
v = u[Range[3]]
v["y"]
v["z"]
and got outputs:
<|"x" -> {2, 4, 6}, "y" :> f$729435 /@ {2, 4, 6},"z" :> (f$729435 /@ {2, 4, 6})[[2]]|>
{4, 16, 36}
16
The results of v["y"],v["z"] are just what I want, but this behavior is uncomfortable in the following ways:
It appears that
fis not evaluated when the result is assigned tov, but is evaluated when specifically callingv["y"]. Because of this, calculation results are unsure just by callingv. Also, if the processing offis complicated, there is a concern that performance will be affected becausefwill run every time an element ofvis accessed.The scope of
fdefined inModuleis leaking, and the definitions multiply with each execution. Example:
s; s; s;
Names["Global`f$*"]
and output:
{"f$", "f$9454", "f$9455", "f$9456"}
The definitions of the form f$* increases each time s is executed.
My naive idea of using Evaluate also didn't work:Evaluate /@ u[Range[3]] or AssociationMap[Evaluate, u[Range[3]]].
I feel like my idea of using RuleDelayed is possibly fundamentally wrong... Is there any elegant solution?
selfApply(which I don't understand the motivation),//AssociationThread[Keys[#],Values[#]]&can evaluate the delayed values. – Lacia Nov 08 '23 at 02:49fis not leaking - it's the designed behaviour. Every timeModuleis evaluated, the local vars will be generated to ensure the uniqueness. Why enclosef? You can simply hide it in some other context. – Lacia Nov 08 '23 at 02:51selfApply@<|diam -> 1., dens -> 3., vel -> 2., area -> Pi (diam/2)^2, flux -> dens*vel*area|>, while I'm not sure if this way is common. – user14061 Nov 08 '23 at 03:53Modulewill be added to the global context. No matter how many times I runModule[{x}, x = 1]; Names["x*"], the result will be {x}, while the example I presented will multiply variables of the formf$*in the context each time it is run. This is what I'm concerned about since it can be interpreted as a kind of memory leak. – user14061 Nov 08 '23 at 04:13f[x_, a_] := Exp[a x]; u[a_] := Module[{s}, s = Mean[a]; selfApply@<|"x" -> a, "y" :> (f[#, s] & /@ "x"), "z" :> "y"[[2]]|> ]; u[Range[3]]– user14061 Nov 08 '23 at 04:34Module[{vars},vars=...,<|keys->vars|>]. – Lacia Nov 09 '23 at 08:45ModuleandSetDelayedalthough I didn't test, see e.g. https://mathematica.stackexchange.com/questions/119403/ and related questions therein. I mean it's somewhat a common phenomenon but not well-documented. – Lacia Nov 09 '23 at 08:57