Re: Nest and Fold don't respect HoldFirst?
- To: mathgroup at smc.vnet.net
- Subject: [mg109229] Re: Nest and Fold don't respect HoldFirst?
- From: Bill Rowe <readnews at sbcglobal.net>
- Date: Sun, 18 Apr 2010 05:57:47 -0400 (EDT)
On 4/17/10 at 6:03 AM, arno.proeme at gmail.com (ap) wrote: >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. >> I get the same error when I use your code and do: f[Range@10] So, problem is Nest evaluates the first time to a list of numbers and operates on this list rather than the global variable that has been modified. And since your f will not work with this type of list the error message gets generated. That is I see the problem as being using the syntax var[[2]]=RandomInteger to change the second value. >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. This sounds like another way to describe the situation. And when I think about this, I don't see how Nest could work differently. If Nest doesn't evaluate its argument, how can the next iteration evaluate correctly? I don't understand why you create a local copy of the global variable you want to change. Instead of writing f as you did why not write it as: f:=(myList[[2]]=RandomInteger[Length@myList];myList) that is write f to operate directly on the global variable to be modified rather than to operate on a local copy of that variable. If I write f in this fashion then Nest[f,myList,3] works as expected with no error messages. But frankly, the entire idea of modify global variables in this manner strikes me as being unwise. I see result as being code that will be difficult to maintain and debug.