Wolfram mathematica 模式测试未优化?

Wolfram mathematica 模式测试未优化?,wolfram-mathematica,pattern-matching,Wolfram Mathematica,Pattern Matching,在准备回应时,我遇到了一个意想不到的问题,这是我自己的行为 请考虑: test = (Print[##]; False) &; MatchQ[{1, 2, 3, 4, 5}, {x__?test, y__}] 我承认以前从未探索过模式匹配的这一方面,我对这一方面似乎效率低下感到不安。这真的和看起来的一样糟糕吗,还是发生了某种自动缓存打印显示为针对该项进行指示 有没有一种更有效的基于模式的方法来编写这篇文章 正确的模式匹配行为是否需要这种冗余级别,为什么 我匆忙地做出了一个错误的断

在准备回应时,我遇到了一个意想不到的问题,这是我自己的行为

请考虑:

test = (Print[##]; False) &;
MatchQ[{1, 2, 3, 4, 5}, {x__?test, y__}]
我承认以前从未探索过模式匹配的这一方面,我对这一方面似乎效率低下感到不安。这真的和看起来的一样糟糕吗,还是发生了某种自动缓存<代码>打印显示为针对该项进行指示

  • 有没有一种更有效的基于模式的方法来编写这篇文章

  • 正确的模式匹配行为是否需要这种冗余级别,为什么


我匆忙地做出了一个错误的断言,但我离开了它,因为下面的好答案解决了这个问题。请在以后的回答中忽略它

很容易证明在其他领域也进行了类似的优化 案例:

(没有打印任何内容。)

假的 在这里,Mathematica甚至从不测试任何元素的
y


这里只是一个快速猜测,但是
{{uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。因此,
{-1,2,3,4,5}
在第一个元素上失败,因此没有打印输出。尝试用
((Print[###];Positive[#])&)替换
正片
,您将看到它的行为方式与第一个模式相同

我认为你关于Mathematica优化模式测试的假设是错误的。考虑模式<代码> {xy},yy}} /COD>。正如您正确地说的那样,
{1,2,3,4,5}
有4种方式可以适应这种模式。如果现在使用
?test
,将模式测试添加到此中,
MatchQ
应返回
True
,前提是4种方式中的任何一种与模式匹配。因此,它必须测试所有可能的选项,直到找到匹配项为止。因此,只有当有积极因素时才进行优化,而不是当模式失败时

下面是对您的示例的一个修改,它使用了
正数
,这表明Mathematica并没有像您所说的那样进行优化:

test2 = (Print@##; Positive@##) &;
MatchQ[{-1, 2, 3, 4, 5}, {x__?test2, y__}]
它打印了4次!如果第一个元素确实为正(因此不必测试其余元素),它将以一个打印正确终止。第二个元素的测试仅在第一个元素为
True
时应用,这就是为什么在您的元素中未应用
y
测试的原因。这里有一个不同的例子:

test3 = (Print@##; Negative@##) &; 
MatchQ[{1, 2, 3, 4, -5}, {x__?test2, y__?test3}]
我同意你的逻辑,如果第一个失败了,那么考虑到每个元素都应该匹配,所有后续的可能性也将失败。我的猜测是Mathematica还没有那么聪明,对
\uuuuuuuu
中的任何一个实现相同的行为要比为每个实现不同的行为更简单。根据您使用的是
\uuuuu
还是
\uuuuu
实现不同的行为将掩盖测试的真实性质,并使调试变得更困难。

好的,我来试试

MatchQ[{1, 2, 3, 4, 5}, {x__?test, y__}]//Trace
显示插槽序列是冗余的,因为只测试了一个元素,在本例中是序列中的第一个元素。e、 g

MatchQ[{1, 2, 3, 4, 5}, {_, x__?test, y__}] // Trace
现在打印3个2。如果将第一个模式更改为BlankSequence,将生成更多排列,其中一些排列具有不同的第一个元素

MatchQ[{1, 2, 3, 4, 5}, {__, x__?test, y__}] // Trace
在最后一个例子中

MatchQ[{-1, 2, 3, 4, 5}, {__?Positive, y__?test}]
第一个元素总是无法通过测试。如果你把这个改成

MatchQ[{1, 2, -3, 4, 5}, {__?Positive, y__?test}]

您将看到更多与您预期相符的内容。

我认为每个人都忘记了测试函数中可能存在的副作用。以下是我认为正在发生的事情:正如Wizard先生和其他人提到的,有几种方式可以匹配模式,只是组合。对于
{x}
{y}
的每个组合,首先测试
x
模式。顺便说一下,定义多个参数的函数(
##
)没有意义,因为正如@Simon所解释的,测试函数分别应用于序列中的每个元素。这也解释了为什么只打印第一个元素(-1):一旦找到第一个不匹配的元素,模式匹配器就会停止并继续测试下一个可用的组合

下面是一个更具说明性的示例:

In[20]:= 
MatchQ[{-1,2,3,4,5},{_,x__?(Function[Print[#];Positive[#]])}]
During evaluation of In[20]:= 2
During evaluation of In[20]:= 3
During evaluation of In[20]:= 4
During evaluation of In[20]:= 5

Out[20]= True
现在它会打印所有这些文件,因为函数会一个接一个地应用于这些文件,就像在本例中一样

现在是问题的关键。在这里,我设置了一个带有副作用的测试函数,它决定在测试第一个元素后改变主意:

Module[{flag = False}, 
  ClearAll[test3]; 
  test3[x_] := 
     With[{fl = flag}, 
        If[! flag, flag = True]; 
        Print[x]; 
        fl
     ]
];
第一个组合(即
{-1},{2,3,4,5}
将被拒绝,因为函数首先给出
False
。但是,第二个组合(
{-1,2},{3,4,5}
)将被接受。这正是我们观察到的:

In[22]:= 
MatchQ[{-1,2,3,4,5},{x__?test3,y__}]
During evaluation of In[22]:= -1
During evaluation of In[22]:= -1
During evaluation of In[22]:= 2

Out[22]= True
图案匹配器一找到匹配项,打印就停止了

现在,从这里可以明显看出,问题和其他一些答案中提到的优化通常是不可能的,因为模式匹配器无法控制测试函数中可能存在的可变状态

在考虑模式匹配时,我们通常将其视为一个独立于评估的过程,这在很大程度上是正确的,因为模式匹配器是系统的一个内置组件,一旦模式和表达式进行评估,它将接管并在很大程度上绕过主评估循环模式匹配功能更强大,但代价是与求值器纠缠在一起。这包括使用
条件
模式测试
,因为这两个是“入口点”将主评估过程转换为与之隔离的模式匹配过程。一旦模式匹配器命中其中一个,它就会在要测试的条件下调用主评估器,然后一切都是可能的。这让我再次看到,当使用
模式进行测试时,模式匹配器是最有效的测试
条件
都不存在,而且模式完全是语法模式——在这种情况下,它可以优化<
MatchQ[{-1, 2, 3, 4, 5}, {__?Positive, y__?test}]
MatchQ[{1, 2, -3, 4, 5}, {__?Positive, y__?test}]
In[20]:= 
MatchQ[{-1,2,3,4,5},{_,x__?(Function[Print[#];Positive[#]])}]
During evaluation of In[20]:= 2
During evaluation of In[20]:= 3
During evaluation of In[20]:= 4
During evaluation of In[20]:= 5

Out[20]= True
Module[{flag = False}, 
  ClearAll[test3]; 
  test3[x_] := 
     With[{fl = flag}, 
        If[! flag, flag = True]; 
        Print[x]; 
        fl
     ]
];
In[22]:= 
MatchQ[{-1,2,3,4,5},{x__?test3,y__}]
During evaluation of In[22]:= -1
During evaluation of In[22]:= -1
During evaluation of In[22]:= 2

Out[22]= True