Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

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?

share|improve this question
2  
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] –  Daniel Lichtblau Apr 3 at 17:03
    
@DanielLichtblau You beat me to it. Why don't you write this as an answer? –  Leonid Shifrin Apr 3 at 17:05

3 Answers 3

up vote 7 down vote accepted

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]
]
share|improve this answer
    
That's very neat and works perfectly ! –  Pisto Apr 4 at 9:03

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]]]
share|improve this answer

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
        ]
    ]
share|improve this answer
    
@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? –  rm -rf Apr 3 at 17:08
    
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. –  Leonid Shifrin Apr 3 at 17:11
3  
Ok, the statement Attributes[f]=Listable is the culprit. You also have to use instead SetAttributes[f,Listable], so that the Temporary is preserved. –  Leonid Shifrin Apr 3 at 17:24
1  
@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 ... –  Leonid Shifrin Apr 3 at 17:35
2  
@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. –  Leonid Shifrin Apr 3 at 17:37

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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