Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

The article mentions many uses of generics but it doesn't go over one of my favorites, which is that parametricity gives you "theorems for free".

For example, I recently wrote a compiler in Ocaml for a scripting language. The type I used for the syntax tree has lots of type parametsrs:

    type ('id, 'str, 'enum) stmtf =
        (* big ADT definition goes here... *)
The 'id type parameter is the type of identifiers (names), 'str is for strings (they get interpolated) and 'enum is for constants.

These type parameters give me some flexibility. When the parser builds the first syntax tree everything is still a string:

    type syntaxtree = (string, string, string) stmtf
and after a pass to bind names the strings get converted to more informative types:

    type boundtree = (nameId, interpolation, string) stmtf
Up to now, we could get this flexibility by being untyped and defining all these fields in stmtf as "void pointer" or "interface". But the generics lets us make everything type safe. Central to this is the "functor map" over stmtf:

    val map_sstmtf:
        id: ('i1 -> 'i2) ->
        str: ('s1 -> 's2) ->
        enum: ('e1 -> 'e2) ->
        ('i1, 's1, 'e1) sstmtf ->
        ('i2, 's2, 'e2) sstmtf
It takes 3 functions telling what to do to the id, str and enum fields, respectively and converts the stmtf by applying those fucntions to each field. The neat thing is that in the implementation of map_stmtf if we forget to apply apply one of these callbacks to one of the fields the code would not typeckeck. The code also won't typecheck if we apply a callback to the wrong field - say apply the "id" callback to a "str" field. This lets us catch at compile time bugs that wouldn't even have been caught at runtime because in the initial syntaxtree both "id" and "str" fields are represented by "string" and are thus prone to being confused with one another. Both of these turned out to be pretty useful as I evolved my language and changed the structure of my syntax tree.

Liberal use of type parameters also gave many other benefits. For example it was trivial to modify the tree to add a line number next to all identifiers, all I had to do was update the type definition and then see the compilation errors to find the parts of my code that had to be updated.

    type syntaxtree = ((position * string), string, string) stmtf
Finally, one extremely neat trick is that you can use type parameters in some places where you would have used recursive types. This pattern is described pretty well in this post I'm linking to and its the sort of thing that you can't really do without generics.

http://lambda-the-ultimate.org/node/4170#comment-63836



Consider applying for YC's Winter 2027 batch! Applications are open till November 2.

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

Search: