There are multiple problems here:
Attempting Part assignment on a non-Symbol, just as the error message states.
Attempting to manipulate a named replacement object as though it were a symbol.
The replacement that takes place in this construct:
f[x_] := head[x, 2, 3]
Is analogous to that of With
:
With[{x = something}, head[x, 2, 3]]
That is, the substitution is made directly and before evaluation, such that the function Head
never even sees an object x
. Look what happens with this:
ClearAll[f,x]
x = 5;
f[x_] := (x = x+2; x)
f[x]
During evaluation of In[8]:= Set::setraw: Cannot assign to raw object 5. >>
Out[]= 5
This evaluates as: (5 = 5+2; 5)
so not only is assignment to 5
impossible, but all instances of x
that appear in the right hand side of :=
are replaced with the value of x when it is fed to f
. Consider what happens if we try to bypass the assignment problem by using a function with side effects:
ClearAll[f, x, incrementX]
incrementX[] := (x += 2)
x = 3;
incrementX[];
x
5
So our incrementX
function is working. But now we try:
f[x_] := (incrementX[]; x)
f[x]
5
incrementX
did not fail:
x
7
Rather, the the value of x
was 5
at the time of evaluation of f[x]
and therefore that is returned.
What does work?
What options do we have for things related to what you are attempting? There are several.
1. Use a Hold attribute
We can set a Hold attribute such as HoldFirst
or HoldAll
on the function, so that we may pass the symbol name to RHS functions, rather than only its value.
ClearAll[heldF]
SetAttributes[heldF, HoldAll]
x = {1, 2, 3};
heldF[x_] := (x[[1]] = 7; x)
heldF[x]
x
<pre>{7, 2, 3}</pre>
<pre>{7, 2, 3}</pre>
We see that both the global value of x
, and the x
expression returned by heldF
are changed. Note that heldF
must be given a Symbol as an argument otherwise you are again attempting {1, 2, 3}[[1]] = 7
.
2. Use a temporary Symbol
As Arnoud Buzing shows, we can also use a temporary Symbol in Module
.
ClearAll[proxyF]
x = {1, 2, 3};
proxyF[x_] := Module[{proxy = x}, proxy[[1]] = 7; proxy]
proxyF[x]
proxyF[{1, 2, 3}]
x
{7, 2, 3}
{7, 2, 3}
{1, 2, 3}
3. Use ReplacePart
We can also avoid symbols completely and just use ReplacePart
:
ClearAll[directF]
x = {1, 2, 3};
directF[x_] := ReplacePart[x, 1 -> 7]
directF[x]
x
{7, 2, 3}
{1, 2, 3}
This can be used for modifications rather than outright replacements as well:
ClearAll[f]
f[l_] := ReplacePart[l, 1 :> l[[1]] ~Append~ 3]
f[{{}, 3}]
{{3}, 3}