如何正确使用Haskell的`parseTimeM`函数?

How to properly use Haskell's `parseTimeM` function?

Haskell 具有函数 parseTimeM,它取代了已弃用的 parseTime 函数。我想前者优于后者的原因是因为它在报告解析错误方面具有更好的灵活性。它可以在封闭的 monad 上调用 fail,而不是 Maybe

所以我试了一下。一、弃用函数:

> parseTime defaultTimeLocale  "%Y" "2015" :: Maybe UTCTime
Just 2015-01-01 00:00:00 UTC

> parseTime defaultTimeLocale  "%Y" "201x" :: Maybe UTCTime
Nothing

太棒了。不出所料。然后, Identity monad:

> runIdentity $ parseTimeM  False defaultTimeLocale  "%Y" "2015" :: UTCTime
2015-01-01 00:00:00 UTC

> runIdentity $ parseTimeM  False defaultTimeLocale  "%Y" "201x" :: UTCTime
*** Exception: parseTimeM: no parse of "201x"

同样在意料之中,因为 Identity monad 没有优雅的故障模式。但是,我希望 Except monad 有所不同,其目的是优雅地捕获错误。

> runExcept $ parseTimeM  False defaultTimeLocale  "%Y" "2015" :: Either () UTCTime
Right 2015-01-01 00:00:00 UTC

> runExcept $ parseTimeM  False defaultTimeLocale  "%Y" "201x" :: Either () UTCTime
*** Exception: parseTimeM: no parse of "201y"

为什么这里会抛出异常?不应该 return Left () 吗?如何按照我认为的方式解析时间,如果要解析的字符串格式不正确,则优雅地 return 出错?

Exceptmtl 的一部分,它是一个 monad 转换器库。转换器的通常风格是为某些行为定义转换器(ExceptT 在这种情况下)并将基本版本表示为类型同义词:

type Except e = ExceptT e Identity

所以你可能会得到一个异常,因为 Exceptfail 必须通过其小 monad 转换器堆栈底部的 Identity monad。

对于 Except e 具体来说,您将如何为 任意 类型 e 实现 fail?由于我们对 e 完全一无所知,我们不能仅凭一个字符串就想出 e 的值,所以 fail 给你一个例外或永远循环。

所有这些都是反对 parseTimeM 依赖 Monad class 中的 fail 风格的一个很好的论据。