如果我在Mathematica中执行以下操作
f[l_] := Module[{}, l[[1]] = Append[l[[1]], 3]; l]
f[{{}, 3}]
我收到错误:
Set::setps: "{{},3} in the part assignment is not a symbol. "
即使l={{}, 3};f[l]
也会出现同样的错误。但我可以f[l_] := Module[{}, {Append[l[[1]], 3],l[[2]]}]
或l = {{}, 3}; l[[1]] = Append[l[[1]], 3]; l
。
你的解释是什么?
答案 0 :(得分:4)
这里有很多问题:
尝试对非符号进行部件分配,就像错误消息所述。
尝试操纵已命名的替换对象,就像它是一个符号一样。
在此构造中发生的替换:
f[x_] := head[x, 2, 3]
类似于With
:
With[{x = something}, head[x, 2, 3]]
即,在评估之前直接进行替换,使得函数Head
甚至从未看到对象x
。看看会发生什么:
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
评估为:(5 = 5+2; 5)
因此不仅无法分配5
,而且x
右侧的所有:=
实例都会被替换为f
将x输入ClearAll[f, x, incrementX]
incrementX[] := (x += 2)
x = 3;
incrementX[];
x
时的值。考虑如果我们尝试通过使用具有副作用的函数来绕过赋值问题会发生什么:
incrementX
5
所以我们的f[x_] := (incrementX[]; x)
f[x]
功能正在运行。但现在我们尝试:
incrementX
5
x
没有失败:
x
7
相反,在评估5
时,f[x]
的值为HoldFirst
,因此会返回。
我们对您尝试的内容有什么选择?有几个。
我们可以在函数上设置一个Hold属性,例如HoldAll
或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>
,这样我们就可以将符号名称传递给RHS函数,而不仅仅是它的值。
x
我们发现x
的全局值和heldF
返回的heldF
表达式都已更改。请注意,{1, 2, 3}[[1]] = 7
必须以符号作为参数,否则您将再次尝试Module
。
正如Arnoud Buzing所示,我们也可以在ClearAll[proxyF]
x = {1, 2, 3};
proxyF[x_] := Module[{proxy = x}, proxy[[1]] = 7; proxy]
proxyF[x]
proxyF[{1, 2, 3}]
x
中使用临时符号。
ReplacePart
{7, 2, 3}
{7, 2, 3}
{1, 2, 3}
我们也可以完全避免符号,只需使用ClearAll[directF]
x = {1, 2, 3};
directF[x_] := ReplacePart[x, 1 -> 7]
directF[x]
x
:
ClearAll[f]
f[l_] := ReplacePart[l, 1 :> l[[1]] ~Append~ 3]
f[{{}, 3}]
{7, 2, 3}
{1, 2, 3}
这可以用于修改而不是直接替换:
{{1}}
{{3}, 3}
答案 1 :(得分:1)
尝试
f[{{}, 3}] // Trace
您看到l
的值在评估之前插入l[[1]] = Append[l[[1]], 3]
位。所以mma正试图评估这个:{{}, 3}[[1]] = {3}
这可能会做你想要的事情
ClearAll[f];
f[l_] := Module[{},
Append[l[[1]], 3]~Join~Rest[l]
]
(我们的想法是避免分配l
的部分,因为在尝试分配之前会评估l
答案 2 :(得分:1)
如果您确实想在模块中使用Part,您可能需要考虑使用临时变量:
f[l_List] := Module[{t = l}, t[[1]] = Pi; t]
和
In[] := f[{1, 2, 3}]
Out[] = {Pi, 2, 3}