Hacker News new | past | comments | ask | show | jobs | submit login

I'm admittedly new to the language, but my convention has been as follows:

Declare types of all named functions (i.e. not lambdas). This serves two purposes.

First, it makes your code more self-documenting. When I look at a function, probably the first thing I want to know is: "What are its parameters?" Type declarations on functions give you a trustworthy and highly readable answer to that question.

Second, it makes type errors easier to understand. If you don't explicitly declare types, the compiler will perform type inference. When your code has a type error, the compiler can infer a nonsensical type for a function, yielding a hard-to-understand error message. If your function has a type declaration, the error message is more likely to point you to where your actual mistake is.

Rarely declare types on anything that's not a top-level function definition. For example, if I want to call (foo (bar baz)), I don't need to add separate type declarations to baz, (bar baz), and (foo (bar baz)), even though each quite possibly has a different type. On the other hand, if you want to remind yourself of the type of some inner expression, or you think it'll make the type errors more readable, you can add the declaration. It won't hurt you.




I've gotten in the habit of explicitly declaring the types of everything I can. As you already mentioned it's a form of (excellent) documentation that I find myself missing in many languages - when writing Python I get frustrated because I have to go dig or debug the type of a value when in Haskell I can simply look for the type declaration (happily Python I think is considering type annotations). If you use Emacs, haskell-mode and ghc-mod + ag or grep have some awesome features for finding type definitions in source, querying hoogle, and lambdabot style de-sugaring and queries.

While type inference is cool, it's only really useful when I'm playing inside GHCi. Also - it can often improve the quality of a program a lot by thinking about your types first, declaring them, then filling out the function definitions (that is often how I do it).


On the flip side, I tend to declare types mostly at the top level. It's nice to be able to change just a few types and have everything else work itself out. There are times it doesn't work and I don't hesitate to add more type annotations then, and when I get weird type errors my first response is go through and decorate it piece by piece.




Consider applying for YC's Spring batch! Applications are open till Feb 11.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: