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

Like quchen said, the comments are for the API documentation. They are documenting that function's use of a type. The type alone frequently will not communicate any semantic meaning. Consider this type signature.

    exp :: Double -> Double -> Double
You don't inherently know from the type which argument is the base and which is the exponent. Double is not a name that you have control over, so we write a comment for it that will automatically show up in the API documentation. They only get names in the implementation.

    exp base exponent = ...
But these names are for the programmer, not the API documentation. You actually want these names to be separate from what is shown in the API docs. Consider this function:

    map :: (a -> b) -> [a] -> [b]
    map _ [] = []
    map f (x:xs) = f x : map f xs
This code is very concise and easy to read. It is easy to read because the names are small and the important thing is the pattern, not the actual meaning of the names. This function is also extremely general, which means that there's not much use in names. Position in the function means more than a name. Here's what it would look at written with "clear" OO-style names:

    map :: (a -> b) -> [a] -> [b]
    map function [] = []
    map function (firstElement:restOfList) = function firstElement : map function restOfList
First of all, we see that sometimes we want to pattern match instead of using a name. GHC would actually give a warning with this code saying that the name "function" in the first case is never used. This is actually a very useful warning that has helped me catch bugs on multiple occasions. Secondly, the "clear" names here completely obscure our ability to understand the code. It's just too much noise. Now, I'm not trying to get into the whole naming debate here. The point I want to make is that there can be good reasons to not show the parameter names in the API documentation, which is why you'll see comments on type signatures for the purpose of auto-generated documentation.



I guess the complaint is that Java-like languages would let you write the type declaration as

  Double exp(Double base, Double exponent)
while the Haskell syntax for types doesn't provide a place to write down names for arguments. Perhaps a nice fix would be to add Agda-style syntax for arrow-types, like

   exp :: (base : Double) -> (exponent : Double) -> Double
At some point we will want to add dependent types anyway. :)


You can relabel Double with a type alias. Really, adding a newtype gives you a sort of partial equivalent of tagged arguments (requires tags, doesn't permit reordering), and might be best practice when there's more semantic content and no clear typical order (eg, you're passing price and quantity to makeOrder, rather than base and exponent to exp). I make a habit of doing this with my C (where a single element struct adds no overhead, much like a Haskell newtype).


Yeah, type aliases can be really useful for some kinds of type documentation. But they seem a bit on the heavy side for one-off things like the exp and map examples.


I agree that it doesn't make sense for exp or map, but not because they are one-off; rather because they are already clear enough that it's not going to add much.

For map in particular what are you going to rename? You can name unbound parameters without a newtype:

    map :: (input -> output) -> [input] -> [output]
might add a bit;

    map :: MapFunction a b -> [a] -> [b]
takes more away than it adds I think.




Join us for AI Startup School this June 16-17 in San Francisco!

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

Search: