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.