Сопоставление с образцом и неудача в вычислениях
Привязывая монадические значения к идентификаторам в нотации do, мы можем использовать сопоставление с образцом так же, как в выражениях let и параметрах функции. Вот пример сопоставления с образцом в выражении do:
justFirst :: Maybe Char
justFirst = do
(x:xs) <– Just "привет"
return x
Мы используем сопоставление с образцом для получения первого символа строки "привет", а затем возвращаем его в качестве результата. Поэтому justFirst возвращает значение Just 'п'.
Что если бы это сопоставление с образцом окончилось неуспешно? Когда сопоставление с образцом в функции оканчивается не успешно, происходит сопоставление со следующим образцом. Если сопоставление проходит по всем образцам для данной функции с невыполнением их условий, выдаётся ошибка и происходит аварийное завершение работы программы. С другой стороны, сопоставление с образцом, окончившееся неудачей в выражениях let, приводит к незамедлительному возникновению ошибки, потому что в выражениях let отсутствует механизм прохода к следующему образцу при невыполнении условия.
Когда сопоставление с образцом в выражении do завершается неуспешно, функция fail (являющаяся частью класса типов Monad) позволяет ему вернуть в результате неудачу в контексте текущей монады, вместо того чтобы привести к аварийному завершению работы программы. Вот реализация функции по умолчанию:
fail :: (Monad m) => String –> m a
fail msg = error msg
Так что по умолчанию она действительно заставляет программу завершаться аварийно. Но монады, содержащие в себе контекст возможной неудачи (как тип Maybe), обычно реализуют её самостоятельно. Для типа Maybe она реализована следующим образом:
fail _ = Nothing
Она игнорирует текст сообщения об ошибке и производит значение Nothing. Поэтому, когда сопоставление с образцом оканчивается неуспешно в значении типа Maybe, записанном в нотации do, результат всего значения будет равен Nothing. Предпочтительнее, чтобы ваша программа завершила свою работу неаварийно. Вот выражение do, включающее сопоставление с образцом, которое обречено на неудачу:
wopwop :: Maybe Char
wopwop = do
(x:xs) <– Just ""
return x
Сопоставление с образцом оканчивается неуспешно, поэтому эффект аналогичен тому, как если бы вся строка с образцом была заменена значением Nothing. Давайте попробуем это:
ghci> wopwop
Nothing
Неуспешно окончившееся сопоставление с образцом вызвало неуспех только в контексте нашей монады, вместо того чтобы вызвать неуспех на уровне всей программы. Очень мило!..