(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
f
is 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 off
is complicated, there is a concern that performance will be affected becausef
will run every time an element ofv
is accessed.The scope of
f
defined inModule
is 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. $\endgroup$f
is not leaking - it's the designed behaviour. Every timeModule
is evaluated, the local vars will be generated to ensure the uniqueness. Why enclosef
? You can simply hide it in some other context. $\endgroup$selfApply@<|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. $\endgroup$Module
will 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. $\endgroup$