A `Bathtub Ducky` instance.

‘a’ is for ‘anything, really’

Where we learn about type parameters and how to use them.

Michel Belleville
Published in
4 min readDec 27, 2018

--

me> Wat.

wat> Waaaaat?

me> What’s an a?

wat> I don’t know. A letter?

me> Yes, but I meant like in List a, Maybe a, Array a, …

wat> Ah, you mean type parameters?

me> I guess so. Last time we talked about types, we saw how to make type constructors that could have values inside, and they look a bit like those…

wat> Sure. In fact, you can use type parameters with the type constructors to have types that can hold anything you want inside. Consider the Maybe type:

type Maybe a
= Just a
| Nothing

wat> See there’s an a in the type declaration (type Maybe a), and in the Just a constructor?

me> Sure. Is a like a type then? Why is it not a capital A?

wat> In a way, a is like a type yes, and in another, it’s not. A type parameter is a placeholder for an actual type, meaning you can use anything instead of a when you create an actual instance of your type. For example, when I want a List instance, I want a List of something the a in List a is that something, at least as long as we don’t know what actual type is needs to be in our actual instance.

me> Wait, I’m confused. You’re saying that a List a is a “list of something but I don’t know what yet”?

wat> Yep. When you want to use it, you’ll have to decide whether it’s a List String, a List Int, or a List Bool, …

me> So a is kind of a keyword for “I don’t know what it is yet”.

wat> More of a “I don’t really care what it is for now, just replace with whatever you need it to be when you want”.

me> But… Why?

wat> Imagine I didn’t have type parameters. Instead of having a List String you’d have to define a ListString type to list strings, a ListInt type when you want to list integers, etc.

me> Ok…

wat> AND you’d have to have functions that can work with each of your ListSomething types. For example:

ListString.length : ListString -> Int
ListInt.length : ListInt -> Int
ListBool.length : ListBool -> Int

me> That sounds like a hassle.

wat> I’m just getting started! Let’s do map:

ListString.mapToListString : (String -> String) -> ListString -> ListString
ListString.mapToListInt : (String -> Int) -> ListString -> ListInt
ListString.mapToListBool : (String -> Bool) -> ListString -> ListBool
ListInt.mapToListString : (Int -> String) -> ListInt -> ListString
ListInt.mapToListInt : (Int -> Int) -> ListInt -> ListInt
ListInt.mapToListBool : (Int -> Bool) -> ListInt -> ListBoolListBool.mapToListString : (Bool -> String) -> ListBool -> ListString
ListBool.mapToListInt : (Bool -> Int) -> ListBool -> ListInt
ListBool.mapToListBool : (Bool -> Bool) -> ListBool -> ListBool

me> 😲

wat> With type parameters, we only have to define a length and a map function:

length : List a -> Int
map : (a -> b) -> List a -> List b

me> I see… When you say they don’t care… they do care, at least a little. For example, the map function won’t work if the transformation you give it can’t work on the type of values in the list, right?

wat> Right! That’s why the signature of map is:

map : (a -> b) -> List a -> List b

me> I see… map takes a transformation from any type of value a to another type of value b and a List of values of type a to give us back a value of type b!

wat> That’s what type parameters are for. Putting one in a type definition or function signature is like saying: “any of all the types that could ever exist can be put instead of this parameter, and it will still work as expected”.

me> Why are we using one-letter names for these parameters? Why can’t we use words instead?

wat> Mostly by habit, and because it makes for shorter signatures I guess. Probably because a lot of programming language, especially functional programming languages have been designed by (and often for) people used to work with single-letter abstractions like in mathematics 😉 In fact, you can use meaningful words instead of single-letter placeholders. For example, the Result type is easier to understand when you use words instead of letters:

- This:
Result error value
= Ok value
| Err error
-- ...reads better than:
Result b a
= Ok a
| Err b

wat> So, when you design your own types, don’t hesitate to give type parameters meaningful names 😃

me> I’ll keep that in mind. Until next time 😃

--

--