Map.lookup 的 Maybe 结果不是使用我的 Monad Transformer 堆栈进行类型检查

The Maybe result from Map.lookup is not type checking with my Monad Transformer stack

我正在阅读以下论文:Monad Transformers Step by Step。在 2.1 节 "Converting to Monadic Style" 中,函数在 Eval1 monad 中被转换为 return Value。这部分功能对我来说没有意义:

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

结果将是 Maybe Value 但是函数的类型签名是:

eval1 :: Env → Exp → Eval1 Value

该函数无法进行类型检查,这个错误对我来说似乎很明显。然而作者明确指出这将起作用:

... the Var case does not need a fromJust call anymore: The reason is that Map.lookup is defined to work within any monad by simply calling the monad’s fail function – this fits nicely with our monadic formulation here.

Map.lookup 的签名看起来不像是为与任何 monad 一起工作而设计的:

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

这篇论文过时了还是我遗漏了什么?如果论文实际上已经过时,为什么 lookup 改为仅适用于 Maybe

谢谢!

您的教程是 2006 年的。它使用 a very old version of Data.Map,其中 lookup 的类型确实是:

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

我认为发生这种变化是因为 failMonad class 中被广泛认为是一个疣。返回 Maybe a 使查找失败明确且易于管理。通过将它隐藏在 fail 后面只是为了拥有一个稍微更方便的类型而使其隐式是非常肮脏的 IMO。 (另见 the question linked to by Ørjan。)

您可以使用 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

请注意 with the upcoming release of GHC 8.8m 上使用的正确约束将是 MonadFail 而不是 Monad