Карты Хаскелла возвращают монаду

Функция поиска в Data.Map и Data.IntMap в настоящее время возвращает значения, завернутые в Maybe with подпись типа

lookup  :: Ord  k => k -> Map  k a -> Maybe  a

Он имел более общий тип

lookup  :: (Monad  m, Ord  k) => k -> Map  k a -> m a

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

Ответ 1

Don lift преобразует элементы Maybe в свои общие аналоги Monad, поэтому, возможно, его следует называть convert или generalize или что-то; -)

Если вы просто хотите использовать lookup главным образом в пониманиях списков и других монадах, которые реализуют fail, вы также можете использовать сопоставление неудачи совпадения шаблонов с fail:

Prelude> [ v | Just v <- return $ lookup "hi" [("ho","silver")] ]
[]
Prelude> [ v | Just v <- return $ lookup "ho" [("ho","silver")] ]
["silver"]

Prelude> do Just v <- return $ lookup "hi" [("ho","silver")] ; print v
*** Exception: user error (Pattern match failure in do expression at <interactive>:1:3-8)
Prelude> do Just v <- return $ lookup "ho" [("ho","silver")] ; print v
"silver"

Ответ 2

последний сделает его гораздо более общим и позволит искать в методах списка

Последнее также более опасно, так как большинство классов монады определяют fail как error. То есть, общий случай не найти элемент на карте - это ошибка завершения программы для большинства монадов. Это, в сочетании с повышенной вероятностью того, что неверный тип контекста будет выведен, означает, что мы склонны препятствовать стилю "монадического отказа".

Есть ли способ воспроизвести это поведение с более новой версией

Действительно, есть! Просто поднимите, возможно, в Monad a, например:

lift :: Monad m => Maybe a -> m a
lift Nothing  = fail "you die now"
lift (Just a) = return a

И теперь вы можете написать, например. lift . lookup

Ответ 3

Для конкретного случая монады списка наиболее простым решением является использование maybeToList:

Prelude> :m +Data.Maybe -- Note: Use "import Data.Maybe" in a program file

Data.Maybe> [ v | v <- maybeToList $ lookup "hi" [("ho","silver")] ]
[]
Data.Maybe> [ v | v <- maybeToList $ lookup "ho" [("ho","silver")] ]
["silver"]