内存解释中的后备文件

时间:2012-07-30 21:40:19

标签: wolfram-mathematica

在另一个帖子The best way to construct a function with memory中,描述了如何在文件中备份函数:

$runningLogFile = "/some/directory/runningLog.txt";
flog[x_, y_] := flog[x, y] = f[x, y] /.
v_ :> (PutAppend[Unevaluated[flog[x, y] = v;], $runningLogFile]; v)

我觉得我理解这里的大部分成分而不明白它是如何工作的。有人可以告诉我这是如何评估的吗?

1 个答案:

答案 0 :(得分:2)

让我们一步一步地评估flog[1, 2] ......

flog [1,2]

评估此表达式时,Mathematica会在问题中给出的1定义中用x替换2y替换flog。这将产生我们巡演的下一步:

flog [1,2] =  f [1,2] /。 v_:> (PutAppend [Unevaluated [flog [1,2] = v;],$ runningLogFile];     v)的

请注意,此处的作业flog[1, 2] = ...flog本身定义的一部分。

/.是一个中缀运算符,它是ReplaceAll函数的替代表示。 ReplaceAll会将替换规则应用于第一个参数的值。坚持这个想法 - 我们会回到它。第一个参数是flog[1, 2] = f[1, 2]。此表达式将评估f[1, 2],然后将结果分配给flog[1, 2]。为了便于讨论,我们假设f[1, 2]返回345。因此,新的定义将添加到flog,即flog[1, 2] = 345。分配后,我们可以检查flog

的定义

flog definition

观察flog最初只有一个定义,但现在它有两个 - 新添加的flog[1, 2]定义缓存该调用的结果。这通常被称为“memoization”。

flog[1, 2] = 345可能会产生为flog建立新定义的副作用,但是,与Mathematica中的每个表达式一样,它也会产生一个值。该值为345,在很多情况下,它将成为ReplaceAll的第一个参数。

ReplaceAll的第二个参数是:>运算符的调用,RuleDelayed函数的中缀表达式。为了使这篇文章保持在一个可管理的大小,我们只需要注意规则在这种情况下评估自己。

所以,现在我们有一个涉及/.来评估......

的表达式

345 /。 v_:> (PutAppend [Unevaluated [flog [1,2] = v;],$ runningLogFile]; v

替换表达式将其第一个参数(345)与替换规则(v_)的模式组件匹配。 v_匹配345(或其他任何内容)并为345提供名称v以便替换。然后,ReplaceAll会将345替换为规则右侧的v的每次出现。结果是要评估的下一个表达式......

(PutAppend [Unevaluated [flog [1,2] = 345;],$ runningLogFile]; 345)

这里我们有两个用分号分隔的表达式。顺便提一下,;是一个扩展为CompoundExpression的中缀运算符。第一个表达式涉及PutAppend,它将第一个参数的值写入名为第二个参数值的文件中。但请注意,第一个参数包含在Unevaluated中。这会抑制对第一个参数的评估,以便将其完全按原样写入文件:flog[1, 2] = 345;。如果当前的Mathematica会话结束,可以将书面表达式读入未来的Mathematica会话,以重新建立flog[1, 2]的记忆结果。

CompoundExpression会丢弃除最后一个之外的所有参数的值。这里,最后一个参数是345。由于我们已经结束了表达式,因此这将是原始调用的最终返回值。也就是说,flog[1, 2]返回345 - 尽管我们看到有副作用将此结果保存到内存和磁盘以供将来参考。

以后调用flog[1, 2]

现在,如果再次调用flog[1, 2],Mathematica将找到新定义flog[1, 2] = 345345将直接返回,没有我们上面讨论过的任何复杂情况。特别是,它甚至不会再次呼叫f[1, 2]。当然,这是这个例子的全部动机。假设f计算成本非常高,证明所有这些体操都是合理的,以尽量减少计算的次数。