关闭 Pattern::patv 是不是安全?
Posted
技术标签:
【中文标题】关闭 Pattern::patv 是不是安全?【英文标题】:Is it safe to turn off Pattern::patv?关闭 Pattern::patv 是否安全? 【发布时间】:2011-12-04 08:03:21 【问题描述】:默认情况下,如果我对 Blank
和 BlankSequence
模式使用相同的名称,Mathematica 会引发警告消息:
f[x_, ___ | x__] := g[x]
Pattern::patv:名称 x 用于固定和可变长度模式。 >> Pattern::patv:名称 x 用于固定和可变长度模式。 >>
但该功能按我的意愿工作:
f[1, 2, 3]
f[1, 2, 3]
g[1]
g[1, 2, 3]
因此,使用Off[Pattern::patv]
并按照我的意愿继续操作是否安全?
我知道有多种不同的、更冗长的方法可以完成相同的任务,我不想分析它们各自的优点。我只对这个特定的安全感兴趣。
【问题讨论】:
@Simon,halirutan,你在包夹我。 :-) 我知道有优点和缺点。我也喜欢编写简洁的代码,我认为模式匹配的这些更有趣的使用是 Mathematica 编码乐趣的一部分。就像中缀一样,我不会试图将这种用法强加给其他人。 @Mr.f[Shortest[x__], ___ | x__] := g[x]
呢?
@belisarius 我承认,这是我没有考虑过的另一种选择。
@Leonid 这听起来有点像精灵会说的话。我还有两个愿望吗?
@Mr.Wizard 恐怕这是最后一个了 :)
【参考方案1】:
您的构造在技术上似乎没问题,但从概念上讲,这是混合变量绑定和模式匹配。换句话说,这依赖于模式匹配器的某些未记录的行为(这不一定是邪恶的,只是要注意)。更糟糕的是,这相当模糊。如果您确定几个月后您自己在更大的上下文中阅读本文不会有任何问题,并且您只为自己使用编写代码,那么我认为没有问题。顺便说一句,另一种选择(正如其他人已经建议的那样):f[x_, ___] := f[x]; f[x__] := g[x]
。此外,将Quiet
包裹在SetDelayed
周围比On/Off
更容易。
编辑
这是我根据@Mr.Wizard 的要求添加的对该问题的扩展视图。免责声明是这些只是推测,它们可能完全或部分错误。
变量绑定阶段是评估范围构造(例如Module
、With
、Block
、Function
)时的一个主要静默阶段。由RuleDelayed
形成的延迟规则也是范围构造,从某种意义上说,模式变量对与其他范围构造的名称冲突具有一定的保护,而且变量绑定也在那里发生。变量绑定是将变量名与某个值关联的过程(通过规则的表达式解构获得)。对于像Module
、With
、Block
、Function
这样的作用域构造,我们可以很好地控制变量绑定,因为我们可以覆盖这些构造的 Hold* 属性,编写类似 x=y;Function[Evaluate[x],y^2]
的内容.对于规则,变量绑定发生在模式匹配器内部,并且不是可控的。通常,您不会过多考虑绑定是如何发生的,要么是因为没有歧义,要么是因为名称冲突解决语义在文档或其他地方有详细说明(例如,对于名称冲突有一个通用规则在嵌套的词法作用域结构中,内部绑定受到青睐)。
对于手头的情况,您受制于规则的变量绑定机制,以及它与模式匹配器交互的方式。关于模式 - 匹配器的一个事实(不知道是否记录在案)是,当给定使用 Alternatives
构建的模式时,它会尝试从左到右匹配。从常识来看,我们应该期望变量绑定发生在匹配之后,因此您的构造很好。然而,这是在挖掘我们无法控制的内部结构。模式匹配器/绑定机制的行为可能没有其他逻辑上一致的方式,或者可能是其他方式。
正如我所说,这本身并不一定是坏事 - 如果我们有一个特性的经验证据,我们通常会依赖一些未记录的行为,并且这个特性允许我们轻松地做一些不平凡的事情.我对这个结构的主要反对意见是它的晦涩难懂——它比使用两个单独规则的代码更难阅读(无论如何对我来说)。
【讨论】:
谢谢列昂尼德。你介意扩展一下,也许有一些关于变量绑定的想法?我知道你一定有更多的东西要写;你总是这样。 :-) @Mr.Wizard 好吧,我对此事添加了一些想法,但不确定它们是否值得。 再次感谢。我一直很欣赏您的意见和分析。 Leonid 我想重写this answer 以消除这种奇怪的方法。请告诉我你会怎么做。 @Mr.Wizard 我会使用这样的东西:PolarParametricPlot[rt : Except[_List], Except[_List], rest__] := PolarParametricPlot[rt, rest]; PolarParametricPlot[rT : _, _ .., uv : _, _, _ .., opts : OptionsPattern[]] := ParametricPlot[Evaluate[# Cos@#2, Sin@#2 & @@@ rT], uv, opts]
。在这种特殊情况下,您的方法确实节省了一些打字并且很优雅,但仍然很难消化:)【参考方案2】:
当你关闭消息然后再次打开时,你写了 3 行来使用你的模式。如果你想表达 f 应该在给定一个列表时取第一个元素,如果给定多个参数则取所有元素,有什么问题
f[x_, ___] := g[x];
f[x__] := g[x];
哪还少写一行?
但是要对您的模式发表意见:我在这里看到的问题是
f[x_, __ | x__] := x;
g[x__ | x_, __] := x;
f[1, 2, 3]
g[1, 2, 3]
Out[6]= 1
Out[7]= 1, 2, 3
这有点出乎意料,而且可能难以调试。使用具有不同模式的两个定义就可以了:
f[x_, __] := x;
f[x__] := x;
g[x__] := x;
g[x_, __] := x
f[1, 2, 3]
g[1, 2, 3]
Out[7]= 1
Out[8]= 1
【讨论】:
感谢您的意见。我说的是通过将Off[Pattern::patv]
放在我的init.m
中来全局关闭消息,因此没有添加行。你展示的是一种非常常见的形式,但有时我更喜欢讨论中的形式。在您的示例中,右侧非常简单,但在实际使用中可能存在大量代码重复。
halirutan:当我在上面发表评论时,我不知道您已经发布了答案。我将问题中的代码与您的答案here 中的代码进行了比较。 (欢迎来到 ***!)
Simon:我是在我发布答案后看到的。
Mr.Wizard:如果你的 g[x] 是一个复杂的 rhs,那么使用类似 f[x_, _] := f[x]; f[x] := g[x];
您更新的答案对我来说更有趣。谢谢你。三个不同的人推荐了:f[x_, ___] := f[x]; f[x__] := g[x];
所以我相信这是规范的方式。关于您的更新,这确实增加了复杂性。然而,这是Alternatives
而非Pattern::patv
的问题,尽管后者可能需要前者。我同意应该避免代码歧义的暗示,但我想指出Alternatives
不再模棱两可,并且可能比 Mathematica 中的其他结构更不模棱两可。 (续)以上是关于关闭 Pattern::patv 是不是安全?的主要内容,如果未能解决你的问题,请参考以下文章