8
$\begingroup$

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?

$\endgroup$
2
  • 2
    $\begingroup$ This slight change to that code might suffice. unflatten[l_, o_] := Module[{f, i = 1, l1 = Flatten[l]}, Attributes[f] = {Listable}; f[_] := l1[[i++]]; ll = f[o]; Clear[f]; ll] $\endgroup$ Apr 3, 2014 at 17:03
  • $\begingroup$ @DanielLichtblau You beat me to it. Why don't you write this as an answer? $\endgroup$ Apr 3, 2014 at 17:05

3 Answers 3

8
$\begingroup$

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]
]
$\endgroup$
1
  • $\begingroup$ That's very neat and works perfectly ! $\endgroup$
    – Pisto
    Apr 4, 2014 at 9:03
6
$\begingroup$

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]]]
$\endgroup$
4
$\begingroup$

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
        ]
    ]
$\endgroup$
12
  • $\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 attribute Temporary. You can make a simple experiment to verify that: Module[{f},f[1] = 1; Clear[f]], and then also try ClearAll, and monitor the existing symbols in Global` 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 instead SetAttributes[f,Listable], so that the Temporary 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 attribute Temporary and it has no DownValues or SubValues (not sure about UpValues, and OwnValues 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 leaves Module (and of course if the return value of Module is not some expression containing this local symbol). Now, originally, there were 2 problems: first, the code Attributes[f] = {Listable} removes the Temporary 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 adds Listable to existing ones, so Temporary is retained. Second, we need Clear at the end, to remove the DownValues which accumulated for f during the execution - then we fulfill both conditions and the symbol is garbage-collected. $\endgroup$ Apr 3, 2014 at 17:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.