Почему фрагментарное определение функции в Haskell зависит от порядка, который они указали?

#haskell

Вопрос:

Будучи новичком, я работаю над примером функции с пошаговым определением.

 pts 1 = 10
pts 2 = 6
pts x = x
 

Приведенный выше код работает так, как я и ожидал. Однако, когда я попытался изменить порядок на

 pts x = x
pts 1 = 10
pts 2 = 6
 

Я получил предупреждение

предупреждение: [-Woverlapping-шаблоны] Совпадение шаблонов является избыточным

и последние два утверждения, похоже, игнорируются компилятором. Мне не удалось найти ответ в Google, я был бы признателен за ссылку на объяснение.

Комментарии:

1. Написать алгоритм, который проверяет, все ли шаблоны непересекающиеся, сложно, а писать шаблоны, которые все непересекающиеся, раздражает. Поэтому вы должны согласиться с тем, что некоторые шаблоны перекрываются, и язык должен указывать, что происходит, когда они это делают. Примерить их в том порядке, в каком их написал программист, — один из естественных вариантов; есть и другие, но большинство из них гораздо сложнее указать и правильно использовать.

2. @DanielWagner ваш комментарий был бы хорошим ответом.

3. @DanielWagner Я полагаю, что можно было бы автоматически упорядочивать шаблоны от наиболее специфичных до наименее специфичных (хотя в менее тривиальных примерах для этого потребуется какое-то лексикографическое соглашение). Только… почему ? Простая схема сверху вниз работает отлично, ее легко понять и отладить.

4. @CalumHalpin, может быть. Я не уверен. С этими «почему происходит X?» на вопросы всегда есть два уровня ответа: «какое правило объясняет такое поведение?» и «почему было выбрано это правило?». Существующий принятый ответ является ответом на первый, что заставляет меня думать, что, хотя он и интересен, ответ на последний на самом деле не имеет отношения к исходному вопросу.

5. @DanielWagner это вполне может иметь отношение к кому-то, кто столкнется с этим вопросом в будущем. В любом случае, это ответ, и ему не место в комментариях.

Ответ №1:

В Haskell шаблоны в определениях функций, подобных этому, проверяются сверху вниз. Итак, ваш первый пример такой же, как:

 pts x =
  if x == 1 then 10
  else if x == 2 then 6
  else x
 

И ваше второе определение похоже на:

 pts x =
  if True then x
  else if x == 1 then 10
  else if x == 2 then 6
  else undefined
 

Очевидно, что в этом втором примере всегда берется первая ветвь, остальные являются избыточными.

Ответ №2:

Хаскелл просматривает шаблоны сверху вниз и выбирает первый, который соответствует входным данным. В этом случае x соответствует любому входу, потому что это просто обычная переменная, поэтому, если она сверху, она всегда выбирается сразу, а другие шаблоны даже не рассматриваются. Это такое решение:

 pts x = if True then x
         else if ... -- irrelevant
 

Если он находится внизу, он рассматривается только после того, как другие шаблоны потерпели неудачу, и поскольку они соответствуют конкретно только одному числу, это будет происходить чаще, чем нет.