了解Mathematica中的模块参数修改

Qia*_* Li 2 wolfram-mathematica

如果我在Mathematica中执行以下操作

f[l_] := Module[{}, l[[1]] = Append[l[[1]], 3]; l]
f[{{}, 3}]
Run Code Online (Sandbox Code Playgroud)

我收到一个错误:

Set::setps: "{{},3} in the part assignment is not a symbol. "
Run Code Online (Sandbox Code Playgroud)

甚至l={{}, 3};f[l]得到相同的错误。但我可以做f[l_] := Module[{}, {Append[l[[1]], 3],l[[2]]}]l = {{}, 3}; l[[1]] = Append[l[[1]], 3]; l

你的解释是什么?

Mr.*_*ard 5

这里有多个问题:

  1. 尝试在非符号上分配零件,就像错误消息指出的那样。

  2. 试图将已命名的替换对象当作符号来处理。

在此构造中发生的替换:

f[x_] := head[x, 2, 3]
Run Code Online (Sandbox Code Playgroud)

类似于With

With[{x = something}, head[x, 2, 3]]
Run Code Online (Sandbox Code Playgroud)

也就是说,替换是在评估之前直接进行的,因此该函数Head甚至不会看到对象x。看看会发生什么:

ClearAll[f,x]
x = 5;
f[x_] := (x = x+2; x)

f[x]
Run Code Online (Sandbox Code Playgroud)
在评估In [8]:= Set :: setraw期间:无法分配给原始对象5。>>

出[] = 5

计算结果为:(5 = 5+2; 5)因此,不仅5不可能分配,而且x:=x的所有实例出现在x 的右侧时,也将x的值替换为x f。考虑如果我们尝试通过使用具有副作用的函数来绕过分配问题,该怎么办:

ClearAll[f, x, incrementX]

incrementX[] := (x += 2)
x = 3;
incrementX[];
x
Run Code Online (Sandbox Code Playgroud)
5

因此,我们的incrementX职能正在发挥作用。但是现在我们尝试:

f[x_] := (incrementX[]; x)

f[x] 
Run Code Online (Sandbox Code Playgroud)
5

incrementX 没有失败:

x
Run Code Online (Sandbox Code Playgroud)
7

而是,值x5在评估时的值,f[x]因此将其返回。


有什么用?

对于与您正在尝试的事情相关的事情,我们有什么选择?有几种。

1.使用保留属性

我们可以在函数上设置诸如HoldFirst或的Hold属性HoldAll,以便可以将符号名称传递给RHS函数,而不仅仅是传递其值。

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>
Run Code Online (Sandbox Code Playgroud)

我们看到的全局值xx返回的表达式heldF都发生了变化。请注意,heldF必须给它一个Symbol作为参数,否则您将再次尝试{1, 2, 3}[[1]] = 7

2.使用临时符号

正如Arnoud Buzing所示,我们还可以在中使用临时符号Module

ClearAll[proxyF]

x = {1, 2, 3};

proxyF[x_] := Module[{proxy = x}, proxy[[1]] = 7; proxy]

proxyF[x]
proxyF[{1, 2, 3}]
x
Run Code Online (Sandbox Code Playgroud)
{7,2,3}
{7,2,3}
{1,2,3}

3.使用ReplacePart

我们还可以完全避免使用符号,而只需使用ReplacePart

ClearAll[directF]

x = {1, 2, 3};

directF[x_] := ReplacePart[x, 1 -> 7]

directF[x]
x
Run Code Online (Sandbox Code Playgroud)
{7,2,3}
{1,2,3}

这可以用于修改,而不是直接替换:

ClearAll[f]

f[l_] := ReplacePart[l, 1 :> l[[1]] ~Append~ 3]

f[{{}, 3}]
Run Code Online (Sandbox Code Playgroud)
{{3},3}