默认情况下,如果我对Blank
和BlankSequence
模式使用相同的名称, Mathematica 会抛出警告消息:
f[{x_, ___} | x__] := g[x]
Pattern::patv: Name x used for both fixed and variable length patterns. >> Pattern::patv: Name x used for both fixed and variable length patterns. >>
然而这个功能按我的意愿运作:
f[{1, 2, 3}]
f[1, 2, 3]
g[1]
g[1, 2, 3]
因此,使用Off[Pattern::patv]
是否安全并继续随意?
我知道各种不同的,更冗长的方法可以完成同样的任务,我不想分析它们各自的优点。我只对这个特定安全性感兴趣。
答案 0 :(得分:6)
你的构造在技术上似乎没问题,但从概念上讲,这是混合变量绑定和模式匹配。换句话说,这依赖于模式匹配器的某些未记录的行为(这不一定是邪恶的,只需要注意)。更糟糕的是,这是相当模糊的。如果您确定在几个月之后在更大的环境中自己阅读本文并且没有任何问题,并且您只编写自己使用的代码,那么我没有看到问题。 B.t.w.,另一种选择(正如其他人已经建议的那样):f[{x_, ___}] := f[x]; f[x__] := g[x]
。另外,Quiet
周围SetDelayed
的包裹比On/Off
更容易。
修改的
这是我对问题的扩展观点,在@WhisWizard的请求中添加了。免责声明是这些只是推测,它们可能完全或部分错误。
变量约束阶段是评估范围构造的主要沉默阶段,例如Module
,With
,Block
,Function
。使用RuleDelayed
形成的延迟规则也是范围构造,在某种意义上,模式变量对与其他范围构造的名称冲突有一定的保护,而且变量绑定也在那里发生。变量绑定是将变量名称与某个值(通过表达式解构获得的规则)相关联的过程。对于像Module
,With
,Block
,Function
这样的范围构造,我们可以很好地控制变量绑定,因为我们可能会覆盖这些变量绑定的Hold * - 属性构造,写x=y;Function[Evaluate[x],y^2]
之类的东西。对于规则,变量绑定发生在模式匹配器内部,并且不可控制。通常,您不会考虑绑定是如何发生的,因为没有歧义,或者因为文档或其他地方拼写了名称冲突解决语义(例如,存在名称冲突的通用规则)在嵌套的词法范围构造中,内部绑定是有利的)。
对于手头的情况,你受到规则的变量绑定机制以及它与模式匹配器交互的方式的支配。关于模式的一个事实(不知道是否记录) - 匹配器是它在使用Alternatives
进行模式构建时尝试从左到右匹配。从常识来看,我们应该期望变量绑定在匹配后发生,因此您的构造很好。然而,这正在挖掘我们无法控制的内部。可能是,模式没有其他逻辑上一致的方式 - 匹配器/绑定机制的行为,或者可能是其他方式。
正如我所说,这本身并不一定是坏事 - 如果我们有一个功能的经验证据,我们经常依赖一些无证件的行为,和这个特征使我们可以轻松地做一些非平凡的事情。我对构造的主要反对意见是它的默默无闻 - 使用两个单独的规则(对我而言),它比使用代码更难阅读。
答案 1 :(得分:5)
当你关闭和之后再打开信息时,你会写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}