Hacker News new | comments | show | ask | jobs | submit login
Haskell: Let the Type Inferencer Work for You (mariosangiorgio.com)
26 points by msangi 1857 days ago | hide | past | web | favorite | 13 comments

I don't get this line -- "the Haskell compiler will complain because we still miss the definition of the type of the function."

That's not true. The compiler will give the function the most general type it can infer, which in this case is

    holds :: Eq a => UnionFindElement a -> a -> Bool
without you needing to specify it in the file.

The point of the article is sound - using the interpreter to ask for types is a great way to work (and often leads to surprising realizations which can lead you to generalize and abstract your code), but the reasoning is spurious. Most of the time, you don't need to supply types in Haskell, as the compiler is perfectly capable of figuring them out for itself.

Most of the time, you don't need to supply types in Haskell, as the compiler is perfectly capable of figuring them out for itself.

I love type inference, but I feel like using it in this way doesn't realize its full potential. My functional background primarily stems from SML (and some Clojure), but the logic I'll use should apply here as well. It's true that the compiler is able to infer the most general type itself, but if you rely on it for this you're ignoring an invaluable tool for predicting the correctness of your code.

There are many times where I've used type inference to show me there's an issue with my code before I even run a single unit-test. I always specify the types of my arguments as well as the return type when writing a function, even though it's not technically required at this point. If I've fully reasoned through what it needs to do then this shouldn't be too difficult. Once I've finished I'll make sure it type-checks. If it does then I'll know the logic throughout my function matches the inputs and outputs I've specified.

That gives you a powerful low-pass filter for knowing whether or not your code is more likely to be correct. If you specify the types when you declare the function and they don't match then your code won't type-check, which results in an exception. If you don't, then depending on the type of error your function might still type-check and compile, but with the wrong type. Then you have no choice but to catch the error with unit tests or, even worse, debugging. The interpreter will certainly give you the type for the code that you've entered, but assuming that it's giving you the type for the code you actually need leaves a powerful tool on the table.

Obviously this doesn't cover every class of error you could have in your code of course, but it in my experience it can be very helpful.

Specifying types is not a bad thing, I also do it myself of course. However, the more general the type signatures are, the more that can be reasoned about what a function can do. i.e. there is a lot more that a function of type Int -> Int -> Int can do than say (Num a) => a -> a -> a. So I try to always use the most generic version of the type I can.

I basically agree with this. I tend to adopt some mixture of the following:

1. Write the function and the type together, and use the type checker to perform an initial check for program correctness.

2. Write the function and the type, but comment out the type, and see if the type checker can infer something more general than the type you supplied.

3. Write the type but leave the function undefined - this gives you a skeleton of your project and lets you write both top-down and bottom-up at the same time, filling in the details later on.

4. Use a function, but leave it undefined and don't give it a type. The type checker can infer a type for it, which often helps you write the function itself.

5. Write the functions but not the type, and let the type checker figure the whole thing out (great for throwaway programs and scripting).

With combinations of these, and a brutal dedication to refactoring and modularisation, I find that I can quickly develop correct, re-usable code.

If you're using emacs with a recent haskell-mode and you have the file loaded into a ghci session, then C-c C-t will get you the same information. (C-u C-c C-t will ask ghci and insert the type signature in the line above)

Thanks, I'm going to fix the post right now.

I have been confused by the fact that I got errors while I was not constraining the type in the right way.

More specifically, you remove your type annotations for the target functions/values entirely, and then ask GHCi what it thinks by loading the module into it.

You should then examine the result and make sure it is correct. In this case, you wrote the type signature incorrectly on an otherwise-correct function, but you will also frequently find that what you wrote is syntactically valid but has a type you did not intend at all, because it is actually wrong. For instance, it's easy to end up missing a parameter passing somewhere and ending up with an unexpected function showing up in the inferred signature.

You can also find that the GHCi-inferred type signature is correct, but not what you particularly wanted. Sometimes you may want to deliberately constrain it to something tighter than it will infer. And the other major case I've seen is that you may want to write the type signature with synonyms you've created; if you fix the type signature with those, GHCi will use them in the future if you ask for the type.

More on how much GHC (and other compilers) can reason about resources (alternatively:infer/thorem prove from type signatures and knowledge about data structures used:





Also, there's djinn

Djinn: "I've written a small program that takes a (Haskell) type and gives you back a function of that type if one exists."

("cabal install djinn" works to install it.)


Don't you want there to be a big warning sign that your references are to bleeding edge academic literature that are NOT implemented in GHC and simply aren't in the works at all?

You can also get type signatures non-interactively with ghc's -ddump-types flag.

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | DMCA | Apply to YC | Contact