PatternTest не оптимизирован?

При подготовке ответа на Неожиданное поведение 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, то данный шаблон не может соответствовать?

Если это так, то почему Mathematica не делает этой простой оптимизации?


Заимствуя пример из ответа Йоды, вот еще один пример того, что кажется избыточной оценкой:

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.

8
задан Community 23 May 2017 в 11:44
поделиться