Reputation: 10855
If I do the following in Mathematica
f[l_] := Module[{}, l[[1]] = Append[l[[1]], 3]; l]
f[{{}, 3}]
I get an error:
Set::setps: "{{},3} in the part assignment is not a symbol. "
Even l={{}, 3};f[l]
gets the same error. But I can do f[l_] := Module[{}, {Append[l[[1]], 3],l[[2]]}]
or l = {{}, 3}; l[[1]] = Append[l[[1]], 3]; l
.
What is your explanation?
Upvotes: 2
Views: 2509
Reputation: 24336
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 options do we have for things related to what you are attempting? There are several.
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
.
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}
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}
Upvotes: 6
Reputation: 15423
If you do want to use Part in your Module, you may want to consider using a temporary variable:
f[l_List] := Module[{t = l}, t[[1]] = Pi; t]
And:
In[] := f[{1, 2, 3}]
Out[] = {Pi, 2, 3}
Upvotes: 1
Reputation: 6520
Try
f[{{}, 3}] // Trace
and you see that the value of l
is inserted into the l[[1]] = Append[l[[1]], 3]
bit before evaluation. So mma is attempting to evaluate this: {{}, 3}[[1]] = {3}
This may do something like you want
ClearAll[f];
f[l_] := Module[{},
Append[l[[1]], 3]~Join~Rest[l]
]
(the idea is to avoid assigning to parts of l
, since l
will be evaluated before the assignment is attempted)
Upvotes: 1