Сравнение с образцом

Материал из ТХАБ.РФ
(перенаправлено с «Pattern matching»)
Перейти к: навигация, поиск

Убрав слово if, мы и с нашими виртуальными «ИЛИ» можем расстаться. В этом случае останется лишь это:

analyzeGold :: Int -> String  -- Одно объявление.
-- И множество определений...
analyzeGold 999 = "Wow! 999 standard!"
analyzeGold 750 = "Great! 750 standard."
analyzeGold 585 = "Not bad! 585 standard."
analyzeGold _   = "I don't know such a standard..."

Мы просто перечислили определения функции analyzeGold одно за другим. На первый взгляд, возможность множества определений одной и той же функции удивляет, но если вспомнить, что применение функции суть выражение, тогда ничего удивительного. Вот как это читается:

     analyzeGold  999          =      "Wow! 999 standard!"

если эта функция применяется тогда этому выражению

                  к этому      она
                  аргументу    равна
     analyzeGold  750          =      "Wow! 999 standard!"

если эта функция применяется тогда другому выражению

                  к другому    она
                  аргументу    равна

...

      analyzeGold _ =      "I don't know such a standard..."

иначе эта функция равна общему выражению Когда функция analyzeGold применяется к конкретному аргументу, этот аргумент последовательно сравнивается с образцом (англ. pattern matching). Образца здесь три: 999, 750 и 585. И если раньше мы сравнивали аргумент с этими числовыми значениями явно, посредством функции ==, теперь это происходит скрыто. Идея сравнения с образцом очень проста: что-то (в данном случае реальный аргумент) сопоставляется с образцом (или образцами) на предмет «подходит/не подходит». Если подходит — то есть сравнение с образцом даёт результат True — готово, используем соответствующее выражение. Если же не подходит — переходим к следующему образцу.

Сравнение с образцом, называемое ещё «сопоставлением с образцом» используется в Haskell чрезвычайно широко. В русскоязычной литературе перевод словосочетания «pattern matching» не особо закрепился, вместо этого так и говорят «*шаблон матчинг». Я поступлю так же.

Но что это за символ подчёркивания такой, в последнем варианте определения? Вот этот:

analyzeGold _ = "I don't know such a standard..."
            ^

С формальной точки зрения, это — универсальный образец, сравнение с которым всегда истинно (ещё говорят, что с ним матчится (англ. match) всё что угодно). А с неформальной — это символ, который можно прочесть как «мне всё равно». Мы как бы говорим: «В данном случае нас не интересует конкретное содержимое аргумента, нам всё равно, мы просто возвращаем строку I don't know such a standard...».

Важно отметить, что сравнение аргумента с образцами происходит последовательно, сверху вниз. Поэтому если мы напишем так:

analyzeGold :: Int -> String
analyzeGold _   = "I don't know such a standard..."
analyzeGold 999 = "Wow! 999 standard!"
analyzeGold 750 = "Great! 750 standard."
analyzeGold 585 = "Not bad! 585 standard."

наша функция будет всегда возвращать первое выражение, строку I don't know such a standard..., и это вполне ожидаемо: первая же проверка гарантированно даст нам True, ведь с образцом _ совпадает всё что угодно. Таким образом, общий образец следует располагать в самом конце, чтобы мы попали на него лишь после того, как не сработали все остальные образцы.