4

在另一个线程The best way to build 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)

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

4

1 回答 1

2

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

鞭打[1, 2]

当计算此表达式时,Mathematica 将替换问题中给出的定义中的1forx2for 。这产生了我们游览的下一步:yflog

flog[1, 2] = f[1, 2] /。v_ :> (PutAppend[未评估[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

鞭打定义

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

flog[1, 2] = 345可能会有为 建立新定义的副作用,flog但是,就像 Mathematica 中的每个表达式一样,它也产生一个值。经过一番折腾后,该值345将成为ReplaceAll.

to 的第二个参数ReplaceAll是运算符的调用,是RuleDelayed函数:>的中缀表达式。为了将这篇文章保持在可管理的大小,我们将简单地注意到规则在这种情况下对自身进行评估。

所以,现在我们有一个涉及/.评估的表达式......

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

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

(PutAppend[未评估[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计算起来非常昂贵,证明所有这些体操都是为了尽量减少计算发生的次数。

于 2012-07-31T03:56:29.070 回答