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 Char
acters; it's an
alias for [Char]
. We can verify this in 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
.