I am using halirutan's code in this thread to unflatten a list. It works very well but the problem is that the Module's local function f
is not deleted when the function returns the output and I consequently end up with hundreds of thousands of copies of the symbol of the form f$xxxx
, which eventually crashes Mathematica. I tried other solutions from the same thread, but they don't seem to work. Is there any workaround?
3 Answers
The creation of an explicit function f
can be completely avoided by using the 3rd argument to Function
. There, you can specify what Attributes
the anonymous function should have and therefore, you can enforce the same behavior as you did for f
.
unflatten[l_, o_] := Module[{i = 1, l1 = Flatten[l]},
Function[Null, l1[[i++]], {Listable}][o]
]
Here is an alternative which is a bit shorter and closer to the original, and still completely free of this leak:
unflatten[l_, o_] :=
Module[{res, f, i = 1, l1 = Flatten[l]},
Block[{f},
SetAttributes[f, Listable];
f[_] := l1[[i++]];
f[o]]]
You can fix that with the following change:
unflatten[l_, o_] :=
Module[{f, i = 1, l1 = Flatten[l]},
SetAttributes[f, Listable];
f[_] := l1[[i++]];
With[{res = f[o]},
Clear[f, l1];
res
]
]
-
$\begingroup$ @LeonidShifrin Thanks, I've changed it, but why do you say it won't work (it worked in my test)? Isn't the
Temporary
attribute only necessary for automatic garbage collection? If I force erase all definitions, is it not the same? $\endgroup$– rm -rf ♦Apr 3, 2014 at 17:08 -
$\begingroup$ It's not, because then this variable is not garbage -collected -
Module
only garbage - collects variables with attributeTemporary
. You can make a simple experiment to verify that:Module[{f},f[1] = 1; Clear[f]]
, and then also tryClearAll
, and monitor the existing symbols inGlobal`
as you do this. $\endgroup$ Apr 3, 2014 at 17:11 -
3$\begingroup$ Ok, the statement
Attributes[f]=Listable
is the culprit. You also have to use insteadSetAttributes[f,Listable]
, so that theTemporary
is preserved. $\endgroup$ Apr 3, 2014 at 17:24 -
1$\begingroup$ @Pisto Well, what happens is that the variable is only collected by
Module
if it has the attributeTemporary
and it has noDownValues
orSubValues
(not sure aboutUpValues
, andOwnValues
are fine. There are also a couple of additional more subtle conditions, but they are not important for this case) at the moment when the execution leavesModule
(and of course if the return value ofModule
is not some expression containing this local symbol). Now, originally, there were 2 problems: first, the codeAttributes[f] = {Listable}
removes theTemporary
attribute ... $\endgroup$ Apr 3, 2014 at 17:35 -
2$\begingroup$ @Pisto ... This happens because it explicitly alters all set of attributes, which is one reason why this form is generally not advisable.
SetAttributes
fixes that, because it only addsListable
to existing ones, soTemporary
is retained. Second, we needClear
at the end, to remove theDownValues
which accumulated forf
during the execution - then we fulfill both conditions and the symbol is garbage-collected. $\endgroup$ Apr 3, 2014 at 17:37
unflatten[l_, o_] := Module[{f, i = 1, l1 = Flatten[l]}, Attributes[f] = {Listable}; f[_] := l1[[i++]]; ll = f[o]; Clear[f]; ll]
$\endgroup$