Mathematica中替换的奇怪行为

4
我的问题是:下面的代码为什么不起作用,我该如何修复它?
Plot[f[t], {t, 0, 2*Pi}] /. {{f -> Sin}, {f -> Cos}}

结果是两个空白图表。相比之下,
DummyFunction[f[t], {t, 0, 2*Pi}] /. {{f -> Sin}, {f -> Cos}}

提供

{DummyFunction[Sin[t], {t, 0, 2 *Pi}],  DummyFunction[Cos[t], {t, 0, 2 * Pi}]}

按照要求进行操作。

以下是我实际操作的简化版。我非常烦恼,即使找到了正确的方式来放置花括号,仍然无法正常工作。

最终,我采取了以下方法,它可以正常工作:

p[f_] := Plot[f[t], {t, 0, 2*Pi}]
p[Sin]
p[Cos]
3个回答

7

作为彼得的Hold/ReleaseHold策略的替代方案,您可以执行以下操作:

Plot[Evaluate[ f[t]/. {{f -> Sin}, {f -> Cos}} ], {t, 0, 2*Pi}]

这样写起来更清晰一些。这确保了在评估Plot之前,将替换f


你甚至不需要使用 Evaluate[],只需将替换移动到 Plot[] 中就足够了。Plot[f[t]/. {{f -> Sin}, {f -> Cos}}, {t, 0, 2*Pi}] - Isaac
@Isaac: 并不总是这样。有时我发现先进行Evaluate是必要的,否则Plot无法如你所愿地运行。 - rcollyer
@rcollyer:是的,这取决于正在替换什么。在这种特定情况下,它按照我说的方式工作,尽管(至少对我来说,在7.0.1.0中)您的代码会将曲线显示为两种不同的颜色,而我的代码会将两条曲线显示为相同的颜色。当然,您的代码和我的代码都会在一个网格上绘制两条曲线,这可能不是原始帖子的意图(也许是两个单独的网格)。 - Isaac
非常抱歉我一直在更改我的已接受答案。我意识到Isaac是正确的:我确实想要两个单独的图。不过你的回答仍然非常有趣。 - Ilya
@Ilya,说实话,我会选择@gdelfino的方法,因为它更透明,只有在更复杂的情况下才使用Hold/ReleaseHold方法。 - rcollyer
1
使用Evaluate意味着替换只进行一次,然后结果被Plot使用;如果没有Evaluate,则每个绘图点都将进行一次ReplaceAll。然后Plot不会执行分析,从而使其自动给出曲线的不同颜色。如果您不是在做简单的事情,它也会变慢——在/.的右侧放置一个NDSolve,如果没有Evaluate,您可能需要喝杯咖啡等待。十有八九,Evaluate是正确的解决方案:例外情况是,如果您尝试Plot的东西需要数字参数才能工作。 - Pillsy

7
这个更短一点:
Plot[#[t], {t, 0, 2*Pi}] & /@ {Sin, Cos}

这非常好!我接受Peter的答案,因为它似乎不像一个谜题,但这绝对是缩短我的“解决方案”到一行的酷方法。 - Ilya
为了进一步游说这种方法(Peter的方法也可以以同样的方式扩展),可以使用MapIndexedMapThread进行扩展,以允许您以不同的方式为每个图形设置样式。此外,它们可以使用Show组合在一起,创建相当复杂的图形。(这是我在数据分析中倾向于采用的方法。) - rcollyer

4

Mathematica试图在替换之前评估Plot函数。你可以使用Hold和ReleaseHold函数来防止这种情况:

ReleaseHold[Hold[Plot[f[t],{t,0,2*Pi}]] /. {{f -> Sin},{f -> Cos}}]

Hold[]将强制整个Plot子表达式在替换执行时保持未简化状态,然后ReleaseHold[]将允许它继续进行实际绘图。


谢谢你的回答。你的解决方案有一个错别字,你应该使用/代替第一个->。它可以工作。然而,对我来说,为什么替换不在优先顺序的最前面并没有太多意义... - Ilya
请将以下有关编程的内容从英语翻译成中文。仅返回已翻译的文本: - Ilya
我无法解释为什么操作顺序是这样的,但这不仅仅是Plot的问题。Mathematica将尝试在执行替换之前评估/左侧的任何函数(对于之前的拼写错误我很抱歉)。很多时候这并不重要:未定义的f[t]将一直被带入函数定义,直到进行替换。例如,myFun[x_, l_] := x /@ l; myFun[f, {1,2,3}] /. {{f->Sin}, {f->Cos}} 将按照您的预期工作。但是,Plot[]是其中一个例子,其中f[t]未定义将导致立即出错。 - Peter Milley
Plot 在规则替换之前进行评估的原因是因为 /. 只是 ReplaceAll 函数的中缀运算符。 因此,f[x] /. x-> y 就是表达式 ReplaceAll[f[x], x->y],而 ReplaceAll 没有任何 Hold* 属性。请参阅此教程以了解更多关于 Mathematica 评估语义的基础知识:http://reference.wolfram.com/mathematica/tutorial/Evaluation.html - Michael Pilat

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接