При подготовке ответа на Неожиданное поведение PatternTest в системе Mathematica я столкнулся с неожиданным поведением системы Mathematica.
Пожалуйста, подумайте:
test = (Print[##]; False) &;
MatchQ[{1, 2, 3, 4, 5}, {x__?test, y__}]
During evaluation of In[1]:= 1 During evaluation of In[1]:= 1 During evaluation of In[1]:= 1 During evaluation of In[1]:= 1
False
Поскольку, как кратко сказано в цитате Саймона из документации:
В форме типа
__?test
каждый элемент в последовательности, сопоставленной__
должен даватьTrue
при применении test.
Мне интересно, почему Mathematica проверяет первый элемент списка четыре раза. Конечно, есть четыре способа составить базовый шаблон {x__, y__}
, и если бы это был тест Условие
, то все элементы, составляющие последовательность x
, должны были бы быть проверены, но я не думаю, что это тот случай.
Не следует ли из логики, что если первый элемент списка не прошел PatternTest
, то данный шаблон не может соответствовать?
Заимствуя пример из ответа Йоды, вот еще один пример того, что кажется избыточной оценкой:
In[1]:= test2 = (Print@##; Positive@##) &;
MatchQ[{1, 2, 3, 4, -5}, {x__?test2, y__?Negative}]
During evaluation of In[1]:= 1
During evaluation of In[1]:= 1
During evaluation of In[1]:= 2
During evaluation of In[1]:= 1
During evaluation of In[1]:= 2
During evaluation of In[1]:= 3
During evaluation of In[1]:= 1
During evaluation of In[1]:= 2
During evaluation of In[1]:= 3
During evaluation of In[1]:= 4
Out[2]= True
Я признаюсь, что никогда раньше не исследовал этот аспект сопоставления шаблонов, и меня беспокоит кажущаяся неэффективность этого. Действительно ли все так плохо, как кажется, или имеет место некое автоматическое кэширование? Print
, похоже, указывает против этого.
Есть ли более эффективный основанный на шаблонах способ написать это?
Требуется ли такой уровень избыточности для правильного поведения сопоставления шаблонов, и почему?
Я сделал ложное утверждение в спешке, но я оставляю его, потому что хорошие ответы ниже касаются этого. Пожалуйста, игнорируйте его в будущих ответах.
Легко продемонстрировать, что подобная оптимизация производится и в других случаях:
MatchQ[{-1, 2, 3, 4, 5}, {__?Positive, y__?test}]
(Ничего не выводится.)
FalseЗдесь Mathematica корректно даже не проверяет ни одного элемента на
y
.