Результат Maybe из Map.lookup не является проверкой типа с моим стеком Monad Transformer

Я собираюсь представить следующую статью: " Монадные трансформаторы шаг за шагом". В разделе 2.1 "Преобразование в монадический стиль" функция преобразуется для возврата Value в монаду Eval1. Эта часть функции не имеет смысла для меня:

eval1 env (Var n) = Map.lookup n env

Результатом этого будет Maybe Value однако сигнатура типа функции:

eval1 :: Env → Exp → Eval1 Value

Функция не может проверить тип, и ошибка кажется мне очевидной. Тем не менее, автор специально заявляет, что это будет работать:

... случай Var больше не нуждается в вызове fromJust: причина в том, что Map.lookup определен для работы в любой монаде, просто вызывая функцию сбоя монад - это прекрасно согласуется с нашей монадической формулировкой.

Подпись для Map.lookup не выглядит так, как будто она предназначена для работы с любой монадой:

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

Эта статья устарела или я что-то упустил? Если статья на самом деле устарела, то почему lookup был изменен, чтобы работать только с Maybe.

Спасибо!

Ответ 1

Ваш урок с 2006 года. Он использует очень старую версию Data.Map в которой тип lookup действительно был:

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

Я считаю, что изменение произошло потому, что fail как считается, является бородавкой в классе Monad. Возврат Maybe a делает ошибку поиска явной и управляемой. Что делает его неявным, скрывая его за fail просто иметь немного более удобный вид сильно загрязнен ИМО. (См. Также вопрос, на который ссылается Орджан.)

Вы можете использовать эту адаптированную версию lookup чтобы следовать этому уроку:

fallibleLookup :: (Ord k, Monad m) => k -> Map.Map k a -> m a
fallibleLookup k = maybe (fail "fallibleLookup: Key not found") pure . Map.lookup k

Обратите внимание, что в следующем выпуске GHC 8.8 правильным ограничением для использования на m будет MonadFail а не Monad.