Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
MakeevGA-Haskell-a4-shortcode_2014_05_31.doc
Скачиваний:
15
Добавлен:
19.01.2023
Размер:
1.79 Mб
Скачать

Тип данных Maybe

Это мой любимый, веселый, самокритичный тип данных, вот как он определяется:

data Maybe a = Nothing | Just a

deriving (Eq, Ord, Read, Show)

Где взять значения этого типа? А вот их примеры:

Nothing :: Maybe a

Just True :: Maybe Bool

Just 1 :: Num a => Maybe a

Just "ice" :: Maybe [Char]

Зачем может быть нужен такой тип? А давайте представим себе функцию, которая ищет значение в ассоциативном массиве по ключу. Пусть есть список кортежей [(a,b)], причем тип a допускает сравнение на равенство. И пусть у нас есть какое-то значение типа a. Мы хотим написать функцию, которая будет искать в списке кортежей пару (a,b), у которой значение a совпадает с искомым, и возвращает значение b из этой пары. Какой должен быть тип у этой функции? Может быть, нужно возвращать просто значение типа b?

lookup :: Eq a => a -> [(a,b)] -> b

Но ведь поиск в массиве может оказаться и неудачным, что возвращать тогда? Может быть, нужно возвращать список значений типа b? Тогда, если функция ничего не нашла, она сможет вернуть пустой список:

lookup :: Eq a => a -> [(a,b)] -> [b]

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

Как раз в таких ситуациях и пригодится тип Maybe. Он как бы дополняет нашу функцию контекстом – дополнительной информацией о том, что функция может и ничего не найти:

lookup:: Eq a => a -> [(a,b)] -> Maybe b

lookup key [] = Nothing

lookup key ((k,v):dict)

| key == k = Just v

| otherwise = lookup key dict

Вот оно: из типа этой функции сразу становится ясно: функция берет значение ключа и словарь, и может быть возвратит значение из словаря, сопоставленное с ключом. Давайте проверим:

lookup 2 [(1,"one"),(2,"two"),(3,"three")] → Just "two"

lookup 4 [(1,"one"),(2,"two"),(3,"three")] → Nothing

А как работать с значениями Maybe String, ведь именно такие значения вернула нам функция? Можно, например, взять и склеить эту строку с другой?

SomeModule> Just "two" ++ " is a lot"

ERROR - Type error in application

*** Expression : Just "two" ++ " is a lot"

*** Term : Just "two"

*** Type : Maybe [Char]

*** Does not match : [Char]

В чем тут проблема? Да в том, что функция (++ " is a lot") ожидает, что ей передадут значение типа String, а ей передают Maybe String. А это, как говорится – две большие разницы. Значение Maybe String нельзя просто так сливать с другой строкой, ведь Maybe String может и пустым, Nothing.

Другими словами, тип возвращаемого функцией lookup значения "заражен" контекстом возможной неудачи lookup, контекстом возможной пустоты. Мы, конечно, можем преобразовать значение этого типа в обычную строку – но мы тогда должны взять на себя ответственность за то, как в обычную строку должно преобразовываться значение Nothing:

maybeToString :: Maybe String -> String

maybeToString Nothing = ""

maybeToString (Just s) = s

Вот теперь можно попробовать и сложить:

maybeToString (Just "two") ++ " is a lot" → "two is a lot"

maybeToString (lookup 3 [(1,"one"),(2,"two")]) ++ " is a lot" → " is a lot"