Skip to content

Type Aliases

Learning about newtype, the C or C++ programmers among you may have felt the urge to point out that we can also define new types in those languages:

typedef int banner_number;

The thing is, this doesn't define a new type at all. It only introduces banner_number as an alias for int. Type aliases can help to improve the readability of our code because if a function has the type

student_record *lookup_student(int id);

it may not be clear what the argument of this function represents, especially if there are multiple IDs used on campus (banner for student records, Net ID for computing infrastructure, CSID for computing infrastructure within Computer Science, ...). The type signature

student_record *lookup_student(banner_number id);

is much clearer. Of course, you can often also resolve ambiguities by naming variables and function arguments appropriately. Here, id is probably a poorly chosen name for the function argument.

But back to type definitions. The important property of type aliases as introduced using typedef in C is that they are just that, aliases for the exact same type. So banner_number and int aren't different types at all; they are simply two names for the exact same type. The compiler allows us to pass a banner_number to any function that expects an int, and vice versa.

Thus, improved readability and, sometimes, introducing shorter names for long and complex types, as in

type Parser a = StateT ParserState IO a

are the only purpose of type aliases. They do not define new types and thus do not help with improving the compiler's ability to catch errors in our code.

In Haskell, we use the type keyword to define a type alias. I mentioned before that the String type in Haskell is nothing but a list of Characters; it's an alias for [Char]. We can verify this in GHCi:

GHCi
>>> :info String
type String :: *
type String = [Char]
    -- Defined in ‘GHC.Base’

As my definition of the Parser "type" above illustrates, it is perfectly fine to define parameterized type aliases. The Parser type takes a type argument a, which is passed through as the third argument of the type constructor StateT.