Re: Nest and Fold don't respect HoldFirst?
- To: mathgroup at smc.vnet.net
- Subject: [mg109243] Re: Nest and Fold don't respect HoldFirst?
- From: Leonid Shifrin <lshifr at gmail.com>
- Date: Mon, 19 Apr 2010 02:48:22 -0400 (EDT)
Hi Arno, My understanding is that indeed, Nest and Fold do not respect the Hold Attributes in the way you outlined. Here is my guess for what's happening: the behavior that you observed is probably just a consequence of the way they (Nest and Fold) work (are implemented): first your function is computed (iterated) by Nest or Fold, and then that result is copied to whatever internal storage Nest or Fold is using to keep the intermediate result of a given iteration. In other words, what you get as an input for the next iteration is already a result stored in that internal storage rather than your initial variable. And when this result is supplied to you for the next iteration, it gets evaluated, so probably what you get is a fully evaluated copy rather than a reference to that storage. This copy is immutable, so you get the error when attempting to modify it. This scenario is just my speculation, any part of it may be wrong. Now, one of the main goals of functional style is to work on immutable structures, so this behavior seems consistent with that ideology. Whenever you use Hold attributes to implement pass-by-reference and in-place modifications, you already step outside of the functional programming paradigm. So I would not hesitate to use loops - in your situation this seems totally appropriate. As far as efficiency is concerned, functional programming is efficient in Mathematica simply because it allows to work with large pieces at once, pushing more operations into the kernel and by-passing the main evaluation loop for many small parts of your expression. In most cases, loops are associated with breaking expression into pieces, and that is what makes them inefficient. In some cases however, loops can be used to the same effect, and then they are no less efficient than functional programming. For your problem in particular, loops should be totally fine. In the case of lists, you may also save a little (like 25 %) by wrapping your values in HoldComplete rather than List, since then no UpValues lookup will take place. Hope this helps. Regards, Leonid On Sat, Apr 17, 2010 at 3:03 AM, ap <arno.proeme at gmail.com> wrote: > Dear group, > > I just wanted to check that I'm correct in thinking that I cannot use > Nest or Fold to iterate a function, where that function has a > HoldFirst attribute set that allows it to modify the global variable > (parameter) passed to it. > As a test case / example I define a function which modifies a global > variable (a list) by setting the 2nd element to a random integer, and > returns the modified list, as follows: > > SetAttributes[f,HoldFirst] > f[var_] := {var[[2]] = RandomInteger[ {0,Length[var]} ], var}[[2]] > > Then if I simply do > > mylist=Range[10] > {1, 2, 3, 4, 5, 6, 7, 8, 9, 10} > > I get > > f[mylist] > {1, 8, 3, 4, 5, 6, 7, 8, 9, 10} > > as expected. > However, if I try to Nest this function to apply it iteratively (as an > alternative to a For or Do loop), as follows: > > Nest[f, mylist, 3] > > I get > > Set::setps: {1,2,3,4,5,6,7,8,9,10} in the part assignment is not a > symbol. >> > > In other words, Nest seems not to respect the HoldFirst attribute of > f. Instead, the list is passed by value and the resulting attempted > assignment of the random integer fails. The same behaviour results > from Fold if I slightly modify f to make it a function of two > variables. > > Is this correct? And if so, is the best alternative simply to use a > loop? That's easy enough, but I was just trying to be as 'functional' > and hence efficient as possible, as this kind of modification of a > global variable is a key step in my algorithm and needs to be as fast > as possible. I have an alternative implementation where instead of > trying to modify the list I Join existing parts of it with the > relevant modified element, but this appears to be ~25% slower than a > simple Do loop to modify the list. > >