Type Signatures in Instances in PureScript

2017-06-05

Recently I sent a pull request to the PureScript compiler enabling type signatures on methods in instances. This is similar to the functionality enabled by the InstanceSigs extension in Haskell. This functionality should be available in the next version of the PureScript compiler, 0.11.5.

This article is for PureScripters who may not be familiar InstanceSigs from Haskell. I will explain what this allows, and why you may want to use it.

What are type signatures in instances?

The following code shows an example of defining a datatype Foo and writing an Eq instance for it:

import Prelude

data Foo = Foo Int String

-- Here is what the Eq class looks like,
-- in case you don't know it off the top of your head:
-- class Eq a where
--   eq :: a -> a -> Boolean

instance eqFoo :: Eq Foo where
  eq (Foo int1 string1) (Foo int2 string2) =
    eq int1 int2 && eq string1 string2

The next version of the PureScript compiler will allow a type signature to be specified for eq in the Eq Foo instance:

instance eqFoo :: Eq Foo where
  eq :: Foo -> Foo -> Boolean
  eq (Foo int1 string1) (Foo int2 string2) =
    eq int1 int2 && eq string1 string2

Why would I want to use this?

There are three main reasons for putting signatures on methods in instances:

  1. Let's think about the example above. The Eq type class is defined in the Data.Eq module. My Foo datatype and the Eq Foo instance may be defined in the module My.Foo. When reading through the My.Foo module, the reader may not have the Data.Eq module open, so they wouldn't be able to check what the type of eq should be. They would have to work it out from the value of the method. This may be somewhat difficult if they are not familiar with the surrounding code.

    As a general rule of thumb, it is helpful for readers of your code if you specify type signatures on instance methods when the type class is not defined in the same module.

    Personally, I like to specify type signatures on instance methods even when the instance is defined in the same module as the type class. People rarely complain about too many type signatures, but it can be a pain reading code with too few type signatures.

  2. Sometimes it is preferable to do "type-driven development" when writing PureScript code. This usually means writing the type signature first and filling in the body of the method afterwards. When writing the body of the method, it is nice to have an explicit type signature to guide your code.

    This is especially nice when you have a type class with multiple parameters and methods with complicated types.

  3. To bring scoped type variables into scope. I show an example of this in the original proposal.

Conclusion

None of the three reasons above absolutely require instance signatures, but instance signatures make it a little nicer to write PureScript code.

tags: purescript