An answer to "The Trouble with Typed Errors"
Tags: Haskell, Variant November 4, 2018

Changelog

  • 2018-11-08 (20h30): I’ve added the “Variant + Either” approach in reaction to a reddit discussion
  • 2018-11-08 (23h00): added section about the FlowT approach

This post is a follow-up to a post Matt Parsons has just published: The Trouble with Typed Errors (discussion on Reddit).

While I totally agree with the diagnostic, I don’t fully agree with the conclusion. in particular:

In PureScript or OCaml, you can use open variant types to do this flawlessly. Haskell doesn’t have open variants, and the attempts to mock them end up quite clumsy to use in practice.

Being the author of an open Variant type (doc) in Haskell, I don’t think they are that clumsy, so let’s compare!

Variant + Either approach

First let’s rewrite the safe functions head, lookup and parse by making them return a Variant on the Left side:

Now to compose these functions, we just have to write:

  1. We can fix the Variant type at the definition site:

Test:

  1. Or if don’t give foo a type signature we can fix the Variant type when we call it:
  1. Or we can give a generic type signature to foo:

It allows us to use TypeApplications to pass the list of error types:

ExceptT-like approach

Just like ExceptT wraps Either, we can use a FlowT newtype to wraps a Variant. Compared to the approach above (“Either + Variant”), we avoid the Either indirection: the first value of the Variant is considered as the Right value and the other ones as the error values.

The example above becomes:

Test:

(FlowT is available from release 2.4 of haskus-utils-variant package).

Full Variant approach

Finally, there is another approach that directly uses Variant with RebindableSyntax extension.

First let’s rewrite the safe functions head, lookup and parse by making them return a Variant:

Now we could use Variant’s primitives to compose these functions (again see the documentation). But instead I will show how we can use them implicitly with do-notation thanks to the RebindableSyntax extension:

Test:

Conclusion

It doesn’t look that clumsy to me! ;-)