Annotation Style


#1

This issue came up in an erratum from the book I’m writing:

This is the kind of annotation I see in most code:

let avg1 = (a: float, b: float): float =>
  (a +. b) /. 2.0;

It is also possible to annotate in the same way you would in an .rei file:

let avg2: (float, float) => float
  = (a, b) => (a +. b) /. 2.0;

The person who filled the suggestion said, “…the second version does not conflate the notion of the function’s TYPE with the parameter names that are being used to support the IMPLEMENTATION (separation of concerns). … it is also the type that is reported in rtop when one defines the function…Interestingly enough at this time refmt doesn’t seem to have an opinion on the style of annotations to prefer as it simply leaves them alone.”

I am curious to know why the first method seems to be preferred, especially since the second method encourages consistency.


#2

The issue actually came up some time ago in reference to Elixir typespecs.

My pet hypothesis is that when people learn to program they are interested in the parameter and return types - the notion of a function itself having a type doesn’t come up until much later - if it even comes up at all unless you are learning Haskell. So therefore having the parameter name and it’s type (UML style) side by side is incredibly convenient for easy correlation.

The notion of a function type only becomes relevant when you start passing functions around as values. But typically those environments are either dynamically typed or have strong type inference capabilities so that the programmer doesn’t have to supply any types manually.

It’s just my experience that not having any practice with wrangling types becomes an issue once the type inference runs into any problems and in its error messages starts to spit out gloriously convoluted type names at you.

Function types become more important once you start to adopt a more type-driven approach towards development:


#3

Wow I had no idea you could it this way. Coming from Elm and Elixir I much prefer this style.

For me its much easier to read and much more likely the the function head stays on one line. I find it hard to read when the function head gets split to multiple lines.

I also think its easier to quickly parse the information I need.

And now I can give type definitions for the fun shortcut functions:

let filterToString: filter => string =
  fun
  | Past => "past"
  | Current => "current"
  | Future => "future";

#4

The first form allows typing a single parameter or a single type of return. While the second form does not allow to take advantage of the inference.

Example:

let avg = (a, b): float => (a +. b) /. 2.0;