3
$\begingroup$

I am trying to define a function f[l_] that will perform an operation on whatever input variable I use (normally I use l which is a list like {2,2,2} or the like) and then reassign the value of the input variable to be the the newly changed list.

The catch is that I'm working within a Module, so the list is adjusted locally within my function f[l_] and the output is the correctly changed list. After I perform the operation, however, the input variable l is still the same: {2,2,2}.

I don't know how to code my function so that the input variable (whether I use l or x or iamstrugglingwiththis as the argument for my function) is changed to be the correct output that is given to me.

$\endgroup$
  • $\begingroup$ possible duplicate of How to modify function argument? $\endgroup$ – Leonid Shifrin Jul 29 '15 at 18:23
  • $\begingroup$ Welcome to Mathematica.SE! I hope you will become a regular contributor. To get started, 1) take the introductory Tour now, 2) when you see good questions and answers, vote them up by clicking the gray triangles, because the credibility of the system is based on the reputation gained by users sharing their knowledge, 3) remember to accept the answer, if any, that solves your problem, by clicking the checkmark sign, and 4) give help too, by answering questions in your areas of expertise. $\endgroup$ – bbgodfrey Jul 29 '15 at 18:23
  • $\begingroup$ So you have, for example, (using x instead of l for readability) f[x_] := x+1. And say t={2,2,2}. Then why not use t = f[t] ? $\endgroup$ – Arnoud Buzing Jul 29 '15 at 19:32
  • $\begingroup$ @ArnoudBuzing the same reason why there is AppendTo or i++ :) $\endgroup$ – Kuba Jul 29 '15 at 19:50
  • $\begingroup$ It's hard to tell where Module is getting in the way of your idea without seeing exactly what you've coded. Please post a minimal working example. $\endgroup$ – Ian Jul 29 '15 at 20:27
1
$\begingroup$

I think that you are looking for something analogous to various modify-in-place functions such as AddTo, AppendTo, PrependTo, AssociateTo, SubtractFrom, Increment, Decrement, but for general function application.

Being aware of Apply and bearing in mind the difference in meaning between simply "function application" and the specific operation of Apply I shall risk to define a function applyTo. Most basically:

SetAttributes[applyTo, HoldFirst]
applyTo[obj_, fn_] := obj = fn[obj]

Now:

a = {2, 2, 2};

applyTo[a, 2 # &];

a
{4, 4, 4}

Since Set works with assignments to Part so does this construct:

applyTo[a[[1]], Sqrt];
applyTo[a[[2]], foo];

a
{2, foo[4], 4}
$\endgroup$
  • $\begingroup$ Our answers are nearly the sam and yours has priority. Do you think I should delete mine for being too similar? $\endgroup$ – m_goldberg Jul 29 '15 at 22:43
  • $\begingroup$ @m_goldberg No, it looks like you cover a different area. I expect I'll be voting for your answer as soon as I read it. $\endgroup$ – Mr.Wizard Jul 29 '15 at 22:56
1
$\begingroup$

I interpret this question as asking how define a function that works like the built-in functions Part, AppendTo, and PrependTo; i.e., a function that performs non-standard argument evaluation because it has been given one of the attributes from the Hold family of attributes.

Normally, in what is referred to as standard evaluation, all the actual arguments passed to a function are evaluated before the function sees them. For a function to able to modify the binding of a global variable it must see that variable's identifier unevaluated. Mathematica provides a mechanism for achieving this with what it calls attributes. For more about standard evaluation, nonstandard evaluation, and attributes mean, you should read the collection of articles found here.

Now I will present an example showing nonstandard evaluation applied to a situation like the one you describe, which involves a module. I have picked a somewhat more elaborate example than Mr.Wizard did in order to illustrate more of the issues that come up when dealing with nonstandard evaluation.

SetAttributes[procrustes, HoldAll];
procrustes[victum_, size_] :=
  Module[{v = victum, n = size},
    If[! (Head[n] === Integer && n > 0), Return[$Failed]];
    If[Head[v] =!= List || v === {}, Return[$Failed]];
    Unevaluated[victum] = If[Length[v] >= size, v[[;; n]], PadRight[v, n, v]];]

Some unit tests

Block[{v = {a, b, c}}, (procrustes[v, #]; v) & /@ {5, 3, 3, 1}]
{{a, b, c, a, b}, {a, b, c}, {a, b, c}, {a}}
Block[{a = 42, b = Pi, c = {}}, procrustes[#, 1] & /@ {a, b, c, 0}]
{$Failed, $Failed, $Failed, $Failed}
Block[{v = {1}, a = 42., b = Pi, c = {}}, procrustes[v, #] & /@ {a, b, c, 0}]
{$Failed, $Failed, $Failed, $Failed}

When defining a function that uses standard evaluation, I make heavy use of argument patterns to validate actual arguments. When defining a function with nonstandard evaluation, I forego that luxury and fall back on procedural argument validation as I have shown here, the reason being that the argument patterns needed become at best awkward in the nonstandard case.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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