【问题标题】:picking specific symbol definitions in mathematica (not transformation rules)在mathematica中选择特定的符号定义(不是转换规则)
【发布时间】:2011-08-23 17:34:34
【问题描述】:

我有以下问题。

f[1]=1;
f[2]=2;
f[_]:=0;

dvs = DownValues[f];

这给了

dvs = 
   {
      HoldPattern[f[1]] :> 1, 
      HoldPattern[f[2]] :> 2, 
      HoldPattern[f[_]] :> 0
   }

我的问题是我只想提取 f[1] 和 f[2] 等的定义,而不是一般定义 f[_],我不知道该怎么做。

我试过了,

Cases[dvs, HoldPattern[ f[_Integer] :> _ ]] (*)

但它什么也没给我,即空列表。

有趣的是,将 HoldPattern 更改为临时^footnote

dvs1 = {temporary[1] :> 1, temporary[2] :> 2, temporary[_] :> 0}

发行

Cases[dvs1, HoldPattern[temporary[_Integer] :> _]] 

给予

{temporary[1] :> 1, temporary[2] :> 2}

它有效。这意味着 (*) 几乎是一个解决方案。

我不明白为什么它适用于临时而不适用于 HoldPattern?如何让它直接与 HoldPattern 一起工作?

当然,问题是评估什么,不评估什么等等。在 Mathematica 中编码时的以太问题。真正的大师的东西......

致以最诚挚的问候 卓然

footnote = 我手动输入它作为替换“/. HoldPattern ->temporary”实际上执行了 f[_]:=0 规则并给出了一些奇怪的东西,我当然想避免这种执行。

【问题讨论】:

    标签: wolfram-mathematica


    【解决方案1】:

    原因是你必须转义HoldPattern,也许是Verbatim

    In[11]:= Cases[dvs, 
                Verbatim[RuleDelayed][
                   Verbatim[HoldPattern][HoldPattern[f[_Integer]]], _]]
    
    Out[11]= {HoldPattern[f[1]] :> 1, HoldPattern[f[2]] :> 2}
    

    只有少数几个头需要这样做,HoldPattern 就是其中之一,正是因为它通常对模式匹配器“不可见”。对于您的temporary 或其他负责人,这不是必需的。注意模式f[_Integer] 被包裹在HoldPattern 中——这次HoldPattern 用于其直接目的——保护模式不被评估。请注意,RuleDelayed 也包含在 Verbatim 中 - 这实际上是 Verbatim 的另一个常见情况 - 这是必需的,因为 Cases 有一个涉及规则的语法,我们不希望 Cases 使用它解释在这里。所以,这是 IMO 一个很好的例子来说明HoldPatternVerbatim。 另请注意,使用HoldPattern 完全可以实现目标,如下所示:

    In[14]:= Cases[dvs,HoldPattern[HoldPattern[HoldPattern][f[_Integer]]:>_]]
    
    Out[14]= {HoldPattern[f[1]]:>1,HoldPattern[f[2]]:>2}
    

    但是,将HoldPattern 用于转义目的(代替Verbatim)在IMO 概念上是错误的。

    编辑

    为了稍微说明Cases 的情况,这里有一个简单的例子,我们使用Cases 的语法涉及转换规则。这个扩展语法指示Cases 不仅要查找和收集匹配的片段,还要在找到它们之后立即根据规则对其进行转换,因此结果列表包含转换后的片段。

    In[29]:= ClearAll[a, b, c, d, e, f];
    Cases[{a, b, c, d, e, f}, s_Symbol :> s^2]
    
    Out[30]= {a^2, b^2, c^2, d^2, e^2, f^2}
    

    但是如果我们需要找到本身就是规则的元素呢?如果我们试试这个:

    In[33]:= Cases[{a:>b,c:>d,e:>f},s_Symbol:>_]
    Out[33]= {}
    

    它不起作用,因为Cases 将第二个参数中的规则解释为使用扩展语法的指令,找到一个符号并将其替换为_。由于它默认搜索级别 1,并且符号在级别 2 上,因此它什么也找不到。观察:

    In[34]:= Cases[{a:>b,c:>d,e:>f},s_Symbol:>_,{2}]
    Out[34]= {_,_,_,_,_,_}
    

    无论如何,这不是我们想要的。因此,我们必须强制Cases 将第二个参数视为普通模式(简单的,而不是扩展的语法)。有几种方法可以做到这一点,但它们都以某种方式“逃避”RuleDelayed(或Rule):

    In[37]:= Cases[{a:>b,c:>d,e:>f},(s_Symbol:>_):>s]
    Out[37]= {a,c,e}
    
    In[38]:= Cases[{a:>b,c:>d,e:>f},Verbatim[RuleDelayed][s_Symbol,_]:>s]
    Out[38]= {a,c,e}
    
    In[39]:= Cases[{a:>b,c:>d,e:>f},(Rule|RuleDelayed)[s_Symbol,_]:>s]
    Out[39]= {a,c,e}
    

    在所有情况下,我们要么避免Cases 的扩展语法(最后两个示例),要么设法利用它来发挥我们的优势(第一种情况)。

    【讨论】:

    • 您的解决方案相当复杂,并且是开放式的,几乎可以从 DownValues 中挑选任何东西。我真的很想了解更多。我还有一个问题。你试图解释为什么 Verbatim 需要包装 RuleDelayed,“这是需要的,因为 Cases 有一个涉及规则的语法,我们不希望 Cases 在这里使用这种解释。”我觉得这是我想了解的非常重要的事情。您能否更详细地解释一下(当然,前提是您有时间和耐心)。
    • 天哪,好尴尬。我刚刚在 Mathematica 文档中检查了 Cases 语法,并且有一种调用它的方法,例如 Cases[expr, pattern -> rhs]。我真正想要的是 Cases[expr, "pattern -> rhs"] 之类的东西。这是你的意思吗?哦,还有一个问题:如果我使用 MatchQ 而不是 Cases,那么我不需要担心这个特定问题,因为 MatchQ 需要严格的模式。它是否正确?例如,可以使用 MatchQ[expr, RuleDelayed[Verbatim[HoldPattern][HoldPattern[f[_Integer]]], _]]],对吗?
    • @zorank 我添加了您要求的解释,请查看我的编辑。
    • @zorank 是的,你可以这样做,例如像这样:Cases[dvs, x_ /; MatchQ[Unevaluated@x, Verbatim[HoldPattern][HoldPattern[f[_Integer]]] :> _]]。这种方法的问题是很容易忘记Unevaluated 部分,这会导致“评估泄漏”——Cases 会在模式匹配期间评估子部分。此外,这种方法可能效率较低,因为它不是纯粹的语法(MatchQ 本身是基于语法的,但Cases 仍然调用评估器来为每个匹配候选者调用它)。不过,我没有进行基准测试——这里的性能影响可能很小。
    • 一个有趣的观察结果:MatchQ[HoldPattern[f[1]] :> 1, Verbatim[HoldPattern][f[_]] :> _] 给出 False。这应该是正确的,因为 MatchQ 没有特殊的语法允许与 Cases 具有相同意义的模式。
    【解决方案2】:

    当然,Leonid 完全回答了为什么您的 temporary 解决方案有效但 HoldPattern 无效的问题。但是,作为对提取 f[1]f[2] 类型术语的原始问题的答案,他的代码有点难看。为了解决提取这些术语的问题,我将只关注定义左侧的结构,并使用FreeQ 搜索所有级别的事实。所以,定义

    f[1] = 1;  f[2] = 2;  f[_] := 0;
    dvs = DownValues[f];
    

    以下所有

    Select[dvs, FreeQ[#, Verbatim[_]] &]
    Select[dvs, FreeQ[#, Verbatim[f[_]]] &]
    Select[dvs, ! FreeQ[#, HoldPattern[f[_Integer]]] &]
    

    产生结果

    {HoldPattern[f[1]] :> 1, HoldPattern[f[2]] :> 2}
    

    如果在 f 的下限值的右侧没有 f[...](或者,对于第一个版本,Blank[])术语,那么上述其中一个可能是合适的。

    【讨论】:

    • 非常感谢西蒙。如果我的理解是正确的,那么这个策略会消除不需要的情况。我只是好奇,为什么它不适用于最后一行?前两行似乎没有必要,但它们可能会有所防范。我很好奇……
    • @zorank:很抱歉造成混乱。所有三行产生相同的结果。你可以选择你想要的。虽然巫师先生的回答更简洁,而且做的事情基本相同。
    • @Simon 我的代码可能很难看,但这是有原因的:) 对于大量定义,它比您的版本快 2-3 倍,这并非偶然 - 我的代码纯粹是语法而你的为Select 中的每个测试调用评估器。这根本不会影响您的解决方案(实际上,我很想发布与您的上一个完全匹配的解决方案,但改变了我的想法,因为严格来说您可能会得到错误的结果 - 如果 r.h.s. 包含模式而不是 l.h.s. -虽然这是不太可能的情况)。此外,对于少量定义,速度并不重要。
    【解决方案3】:

    基于西蒙的优秀解决方案here,我建议:

    Cases[DownValues[f], _?(FreeQ[#[[1]], Pattern | Blank] &)]
    

    【讨论】:

    • +1 使用BlankVerbatim[_](即Verbatim[Blank[]])好得多!
    • 那是快速而优雅的。如果我的理解是正确的,它会选择表达式的 lhs 不包含任何模式的情况。只是一个问题,为什么在 FreeQ 调用中也需要“空白”?这会很难解释吗?我的意思是,空白不是一种模式吗?
    • @zorank,有必要捕获f[_] := 这样没有命名Pattern的情况,比如f[x_] := Blank 本身可能就足够了,但保留Pattern 更可靠。 -------- 如果您认为Blank_ 相同,则不是; _FullForm 实际上是 Blank[],是的,这是不同的。
    • @Mr.Wizard:非常感谢。我只是好奇,将_____ 设置为向下值会导致一些问题,例如FreeQ 会错过这样的模式吗?
    • @zorank 这是一个很好的观点。需要添加BlankSequenceBlankNullSequence 以获取具有这些但在左侧没有命名模式的定义。你也可以有这样的定义:f[1 ..] :=,你需要Repeated。所有这一切都使这个解决方案变得不那么优雅。当然,匹配整数的 only 定义更容易,但我想提供也适用于其他类型的解决方案。 (f["string"] :=f[0, Pi]:= 等)最终我想你必须决定是包容性过滤器还是独占性过滤器对你更有意义。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多