Skip to content

Miscellaneous

Replace vs. ReplaceAll

ReplaceAll 的策略是从外到内、广度优先的,匹配完的子表达式不再被匹配; Replace 访问表达式的策略是从内到外、深度优先的。 此外,Replace 的默认选项为 Heads->False。 例如

ReplaceAll[f[f[x]],f[x_]:>g[x]]

ReplaceAll[f[f[x]],f->g]

Replace[f[f[x]],f[x_]:>g[x],All]

Replace[f[f[x]],f->g,All,Heads->True]
Out[]= g[f[x]]

Out[]= g[g[x]]

Out[]= g[g[x]]

Out[]= g[g[x]]

对于 ReplaceAll 而言,一方面,规则 {x_head:>x,...} 可以防止 Headhead 的子表达式被匹配,称为哑规则 (dummy rule);另一方面,其余的规则应避免此类不改变表达式的行为,以防止子表达式被遮蔽。例如

ReplaceAll[{f[x],x},{x_f:>x,x->y}]
Out[]= {f[x],y}

With|ReplaceAll 等函数可将表达式注入到带有 HoldAll 属性的函数中。其中,注入规则 (injection pattern) 是一个比较灵活的技巧,

ReplaceAll[Hold[1+1],Hold[x_]:>Hold[x,x]]
Out[]= Hold[1+1,1+1]

RuleCondition 是一个常用且稳定的无文档函数,可实现替换时的计算 (in-place evaluation)。例如

ReplaceAll[Hold[f[x]],f[x_]:>Identity[x]]

ReplaceAll[Hold[f[x]],f[x_]:>RuleCondition@Identity[x]]
Out[]= Hold[Identity[x]]

Out[]= Hold[x]

Helper function

复杂的主体函数应分层,最外层提供用户接口,若干内层的 helper 函数实现不同功能,尽可能使函数的依赖关系为 tree-like 的结构。为了避免重复判定条件,仅在最外层使用判别函数。

Hold-like attributes

需注意 HoldAll 或类似属性在多层函数之间的正确传递。

Set in package

Set 出现在扩展包中时,需注意相关符号在扩展包多次被调用后的状态,或在定义前清除原始值。

Decoupling

减少不同功能的函数与扩展包之间的关联。

Ownvalues are hard to manage

公共符号应避免直接定义为 foo=...foo[]=... 是更好的选择,原因在于:

  • 不具有扩展性。

  • HoldAll 等非标准计算的交互具有技巧性;

Names

直到14.0版本,Names[{"ctx`*"}] 会搜索多层的上下文,Names["ctx`*"] 仅搜索一层,因此更快。例如 ctx`sub`fun 不会被后者搜索到。