Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Haskell has the function parseTimeM, which replaces the deprecated parseTime function. I suppose the reason why the former is preferred over the latter is because it has better flexibility in reporting parse errors. Instead of a Maybe, it can call fail on the enclosing monad.

So I tried it. First, the deprecated function:

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

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

Great. As expected. Then, the 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"

Also expected, since the Identity monad doesn't have an elegant failure mode. But, I expected something different with the Except monad, the purpose of which is to gracefully catch errors.

> 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"

Why is the exception being thrown here? Shouldn't it return Left () ? How do I parse a time like I think it should, which is to gracefully return an error if the string to be parsed is poorly formatted?

like image 457
Ana Avatar asked Oct 20 '22 12:10

Ana


1 Answers

Except is part of the mtl, which is a monad transformer library. The usual style with transformers is to define the transformer for some behavior (ExceptT in this case) and express the base version as a type synonym:

type Except e = ExceptT e Identity

So you are probably getting an exception because the fail for Except has to go through the Identity monad at the bottom of its little monad transformer stack.

With Except e specifically, how would you implement fail for an arbitrary type e? Since we don't know anything at all about e, we can't just conjure up a value of e given a string, so fail would have to give you an exception or loop forever.

All this is a pretty good argument against the parseTimeM style of relying on fail in the Monad class.

like image 101
Tikhon Jelvis Avatar answered Oct 23 '22 01:10

Tikhon Jelvis