How do I keep Haskell's Strong Typing Flexible?
Asked Answered
S

1

7

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?).

Stigmasterol answered 10/2, 2012 at 6:10 Comment(4)
That seems a bit strange. What exactly are you doing that breaks all the code ? Are you changing your types continually ? Usually one would fix itself on one design for its types after a time (or even in the beginning), and most of the work would be on the rest of the code (which in a properly written Haskell should be amazingly independent). Note also that if you're adding constructors to your type, it isn't surprising that the code that handle that type breaks and the compiler is helpful in pointing out potential problems, though generics can help if it shouldn't break the code...Paraesthesia
Perhaps you need to make some type synonyms or type definitions so your changes can be localized to one spot?Navarro
Can you give some example of what are trying to achieve and how would you expect it should behave?Tavarez
It's hard to give an example due to the size/complexity of my code...Perhaps this is a bad sign :/. It would seem that removing the monomorphism restriction solves the problem (and ghci provides more generic typedefs). Things that make sense (to me) like changing a type from RealFrac to Real, has alot of consequences, and once I chase those down, there always seems to be more, and I am lost in a typed version of DLL hell. Change one, the other breaks, Change the other . . .Stigmasterol
P
7

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.

This is actually advertised as a feature in Yesod (a Haskell web framework). Suppose I have specified the following routing specification:

/blog/#String         BlogR   GET

And I decide I want to change it to

/blog/#Date/#String   BlogR   GET

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 getBlogR function - changing its input type so it also accepts a Date. 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.

ghci> let shew = show
ghci> :t shew
shew :: () -> String
ghci> :t show
show :: Show a => a -> String

It is sometimes true that ghci chooses annoying defaults. This, however, can be alleviated.

ghci> :set -XNoMonomorphismRestriction
ghci> let shew = show
ghci> :t shew
shew :: Show a => a -> String

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.

Patrilocal answered 10/2, 2012 at 16:33 Comment(4)
Having said all this, the real answer to your question is probably what augustss suggested: type synonyms and type definitions to clean up your code.Patrilocal
Awesome! My problem is that the type system is so complex that for a beginner I make a best guess at the signature, and end up just asking ghci. (My current issues are with the number typeclasses).Stigmasterol
Is there a way to tell GHCI or a linting program to compare my hardcoded definitions with what might be a better more generic version?Stigmasterol
I don't know of any tool that does that. Usually it's just 1) comment out the type signature 2) see what ghci says. You may need to disable the monomorphism restriction for your file (:set only does it for functions that are defined in ghci) by putting this incantation at the top of your file {-# LANGUAGE NoMonomorphismRestriction #-}Patrilocal

© 2022 - 2024 — McMap. All rights reserved.