I have been writing a growing code base in Haskell. My problem is that I have added type signatures to functions based on what GHCI tells me they should be.
The problem is now that I have a growing codebase, as soon as I change one thing, my code breaks all over the place and I am consumed with tracking down all of the problems.
Are the types derived by loading a module in ghci too specific? How do I decide which type or type classes to use in my signatures to leverage the power of strong typing with some flexibility? (i.e. not spending an hour propagating minor changes?).
This is actually advertised as a feature in Yesod (a Haskell web framework). Suppose I have specified the following routing specification:
And I decide I want to change it to
As soon as I make this change to the routes, the compiler will tell me everywhere that I have broken my code. I will be forced to update the
getBlogRfunction – changing its input type so it also accepts aDate. I will also be forced to update any place where I use type safe URLs in my templates, which would look something like@{BlogR (slug p)}->@{BlogR (date p) (slug p)}.This is considered a Good Thing, because the type checker is helping you to find problems introduced by the changes you made.
Now, regarding ghci.
It is sometimes true that ghci chooses annoying defaults. This, however, can be alleviated.
While using ghci to discover the type of a function is great for beginners, I wouldn’t recommend relying on ghci. Learn what the type signatures mean, and how to discover them yourself. In fact, start writing a function by first writing the type signature you intend it to have. It only takes a small investment of time to learn this skill, and it is a great boon to programming when you can use Haskell’s type system to your advantage.