了解 Mathematica 中的模块参数修改

发布于 2024-12-17 13:29:11 字数 412 浏览 3 评论 0原文

如果我在 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]] = 追加[l[[1]], 3];升。

你的解释是什么?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

幸福还没到 2024-12-24 13:29:11

这里存在多个问题:

  1. 尝试对非符号进行部件分配,正如错误消息所述。

  2. 尝试像操作符号一样操作命名替换对象。

此结构中发生的替换:

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
5

所以我们的incrementX函数正在工作。但现在我们尝试:

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

f[x] 
5

incrementX 没有失败:

x
7

相反,在计算 f 时,x 的值为 5 [x],因此被返回。


有什么作用?

对于与您正在尝试的事情相关的事情,我们有哪些选择?有好几个。

1. 使用 Hold 属性

我们可以在函数上设置一个 Hold 属性,例如 HoldFirstHoldAll,这样我们就可以将符号名称传递给 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>

我们看到 x 的全局值和 heldF 返回的 x 表达式都发生了变化。请注意,必须为 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
{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
{7, 2, 3}
{1, 2, 3}

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

ClearAll[f]

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

f[{{}, 3}]
{{3}, 3}

There are multiple problems here:

  1. Attempting Part assignment on a non-Symbol, just as the error message states.

  2. 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}
So要识趣 2024-12-24 13:29:11

尝试

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 将在尝试分配之前进行评估)

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)

2024-12-24 13:29:11

如果您确实想在模块中使用 Part,您可能需要考虑使用临时变量:

f[l_List] := Module[{t = l}, t[[1]] = Pi; t]

并且:

In[] := f[{1, 2, 3}]

Out[] = {Pi, 2, 3}

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}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文