But the thing is, in C a geocoding function would probably receive two ints and return a string, while in Haskell you'd probably have a function of type "Location -> Address". The type system obviates much of the need for those comments.
Indeed, a solid type system would remove some of that need, in C it can be very important to document what precisely that pointer is pointing to. Is it a provided buffer, something allocated and returned? Multiple or single element? etc etc.
I'm guessing Haskell doesn't need that? A simple statement of purpose would still help though?
I also like to add doxygen headers to functions, but have stopped adding the inputs and outputs. Refactorings causes the doxygen to go out of sync with the code.
In C at least, I think it's important to specify whether we're expecting a pointer to a single element, a pointer to an array, if the pointer is an output, etc etc. A uint8_t* could be many things...
It allows you to document the intended inputs and outputs of the function and state its purpose. This increases maintainability and reusability.
Functions themselves should be short and written as a sequence of logical steps.
I'm also a big fan of doing things right rather than just hacking until it works, which seems to put me in a minority.