Карты Хаскелла возвращают монаду
Функция поиска в 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"]