From: James Stein on 8 May 2010 07:06 I think the scanty procedures below show unexpected, perhaps buggy, behavior. These two procedures work as expected: f assigns a value to a variable passed in by g: *Input:* ClearAll [f, g]; f [lhs_, rhs_] := lhs = rhs; g[rhs_] := Module[{localVar}, f [localVar, rhs]; Print["g: localVar=", localVar]; ]; g[44]; *(printed) Output:* g: localVar= 44 But this method, where f receives the variable differently, fails: *Input:* ClearAll [f, g]; f [lhs_List, rhs_] := lhs[[1]] = rhs; g[rhs_] := Module[{localVar}, f [{localVar}, rhs]; Print["g: localVar=", localVar]; ]; g[44]; *(printed) Output:* g: localVar=localVar$313085 In addition, there is an error message: Set::setps : (localVar$313085} in the part assignment is not a symbol. which is curious because: Head[localVar$313085] returns Symbol. My motivation here is to allow a procedure to return one or more subsidiary results in variables provided by the caller.
From: schochet123 on 9 May 2010 07:49 Set ( = ) does not evaluate its first argument (the lhs) by default, so you need to use Evaluate to tell it to do so. Just replace lhs[[1]] = rhs by Evaluate[lhs[[1]]]=rhs Steve On May 8, 2:06 pm, James Stein <mathgr...(a)stein.org> wrote: > > But this method, where f receives the variable differently, fails: > > *Input:* > > ClearAll [f, g]; > f [lhs_List, rhs_] := lhs[[1]] = rhs; > g[rhs_] := Module[{localVar}, > f [{localVar}, rhs]; > Print["g: localVar=", localVar]; > ]; > g[44]; > > *(printed) Output:* > > g: localVar=localVar$313085 > > In addition, there is an error message: > > Set::setps : > > (localVar$313085} in the part assignment is not a symbol. > > which is curious because: > > Head[localVar$313085] returns Symbol.
From: Leonid Shifrin on 9 May 2010 07:50 Hi James, The behavior you observed in not buggy and also not unexpected when you know the mechanics of Mathematica evaluation. You are obviously trying to implement pass-by-reference in your function calls. To do that in Mathematica, you need to give your functions Hold* - attributes, covering those arguments that you want to pass by reference. If you don't, the arguments get evaluated before they are used in the body of your function, and then instead of variables your function will work with (often immutable) copies of their content (their values). Attempt to modify these copies will often cause error messages. Your first call is fine because the local variable does not have a value initially, and because you only call <f> once. But try this for instance: In[1] = ClearAll[f, g]; f[lhs_, rhs_] := lhs = rhs; g[rhs_] := Module[{localVar}, f[localVar, rhs]; f[localVar, rhs]; Print["g: localVar=", localVar];]; g[44]; Set::setraw: Cannot assign to raw object 44. >> g: localVar=44 And, sure enough, you get an error since by the time we call <f> second time, your <localVar> already has a value. Since <f> did not hold its arguments, localVar evaluated to that value, and the second call was then completely equivalent to calling f[44,44]. Fixing the behavior in the first case is easy: just set a HoldFirst attribute for <f>: SetAttributes[f, HoldFirst];, and it will work. Fixing the second example is harder, because when you use assignment of the form expr[[1]] =rhs, (so called Part assignment), Mathematica expects <expr> to be a Symbol whose value (technically called OwnValue) is a list (or, more generally, normal expression which has a first part). In your case, you have not a symbol but an expression {localVar}, so this won't work even when we fix the problem with Hold*-attributes. There are several ways to fix this, but which one is best depends on what exactly you wish to accomplish. Generally pass-by-reference is discouraged in Mathematica programming (there are exceptions), and in any case to implement it in less trivial cases (like your second one) you will need to understand the Mathematica evaluation process and know how to work with held expressions. I will show just one example: a function that takes a list of values and a sequence of variables of the same length, and assigns values to variables: ClearAll[setMany]; SetAttributes[setMany, HoldRest]; setMany[values_List, vars___] /; Length[values] == Length[Hold[vars]] := Set @@ Hold[{vars}, values] This uses the special form of simultaneous assignment available in Mathematica, like {a,b,c} = {1,2,3}. For example: Clear[a, b, c]; setMany[{1, 2, 3}, a, b, c]; {a, b, c} {1, 2, 3} Here is how you could use it: Clear[g]; g[rhs_] := Module[{localVar1, localVar2}, setMany[{rhs, rhs^2}, localVar1, localVar2]; Print["g: localVar1=", localVar1]; Print["g: localVar2=", localVar2]]; g[3] g: localVar1=3 g: localVar2=9 You may want to look at http://www.mathprogramming-intro.org/book/node173.html and http://www.mathprogramming-intro.org/book/node207.html where I dwell on the topic of parameter-passing in Mathematica, and at http://www.mathprogramming-intro.org/book/node205.html where I try to explain what Hold attributes are. I however do not explain how to work with held expressions. Working with held expressions is explained well in the books of Roman Maeder (Programming in Mathematica), and David Wagner (Power programming in Mathematica: the kernel). The latter is unfortunately out of print. Hope this helps. Regards, Leonid On Sat, May 8, 2010 at 4:06 AM, James Stein <mathgroup(a)stein.org> wrote: > I think the scanty procedures below show unexpected, perhaps buggy, > behavior. > > These two procedures work as expected: > f assigns a value to a variable passed in by g: > > *Input:* > > ClearAll [f, g]; > f [lhs_, rhs_] := lhs = rhs; > g[rhs_] := Module[{localVar}, > f [localVar, rhs]; > Print["g: localVar=", localVar]; > ]; > g[44]; > > > *(printed) Output:* > > g: localVar= 44 > > > But this method, where f receives the variable differently, fails: > > > *Input:* > > ClearAll [f, g]; > f [lhs_List, rhs_] := lhs[[1]] = rhs; > g[rhs_] := Module[{localVar}, > f [{localVar}, rhs]; > Print["g: localVar=", localVar]; > ]; > g[44]; > > > *(printed) Output:* > > g: localVar=localVar$313085 > > > In addition, there is an error message: > > Set::setps : > > (localVar$313085} in the part assignment is not a symbol. > > which is curious because: > > Head[localVar$313085] returns Symbol. > > > My motivation here is to allow a procedure to return one or more subsidiary > results in variables provided by the caller. > > >
From: Richard Fateman on 9 May 2010 07:51 James Stein wrote: .... > > > My motivation here is to allow a procedure to return one or more subsidiary > results in variables provided by the caller. I suggest you re-think this motivation, since it leads to subtle bugs, and is probably difficult to do in Mathematica. I suggest you have a routine return a list of values. You can pick them out this way.. > {a,b,c} = {1,2,3} assigns values to a and b and c. This design abides more by functional abstraction. I haven't looked at the details of your example, but Mathematica's evaluation of names that are locally bound is a mess. Good luck. >
From: James Stein on 11 May 2010 06:27 Leonid: Thank you for your careful explanation; very helpful. I was mystified by the error message, which seemed to complain that a symbol was not a symbol! But now, it makes perfect sense! Richard: In my actual situation (not the simple case I described), the function in question was already returning a list of values; which is why my misguided idea occurred to me. Thanks for your sugestion.
|
Pages: 1 Prev: Variables in Iterator limits? Next: How to write reports and books in Mathematica |