If you've used Elm for more than a few weeks it's almost inevitable that you've used type variables with types such as List a or Maybe a. If you feel confident using data structures with type variables but you don't quite feel comfortable adding type variables to your own data structures then this drip is for you. We will focus on utilizing type variables to produce more reusable code. Let's jump right in.

Let's say we want to make a basic data structure that can represent a hierarchy of files and folders, our first stab at an implementation may look like:

-- A file / folder name, type alias for clarity below.
type alias Name =

type File
    = File String

type Folder
    = Folder (Dict.Dict Name File) (Dict.Dict Name Folder)

-- `Folder` represents the root of the fs
type FS
    = FS Folder

This is not a bad first attempt and these types can already be useful to us:

file1 =
    File "Hello World"

folder1 =
    Folder Dict.empty Dict.empty

folder2 =
        (Dict.fromList [ ("file1", file1 ) ])
        (Dict.fromList [ ("folder1", folder1 )])

But an immediate problem arises, what if there is metadata that we need to associate with the files/folders/fs. Perhaps in every folder we need to keep track of whether it is open. We could hardcode this into our data structure but we would end up creating many repetitive types every time our metadata requirements change, this is analogous to not having the Maybe a type and instead continuously implementing new MaybeX types such as MaybeString and MaybeInt...it would be terrible - we would need to implement functions such as map multiple times, once for each new MaybeX type that we create.

So let's add 3 levels of metadata to our data structure to make it more reusable:

type alias Name =

type File metadata
    = File String metadata

type Folder folderMetadata fileMetadata
    = Folder
        (Dict.Dict Name (File fileMetadata))
        (Dict.Dict Name (Folder folderMetadata fileMetadata))

type FS fsMetadata folderMetadata fileMetadata
    = FS (Folder folderMetadata fileMetadata) fsMetadata

We now have a basic generic file structure! If we wanted to add metadata to each folder to check whether it is open we can do that now:

folderWithMetadata =
    Folder Dict.empty Dict.empty { open = True }

Using type variables in Elm allows us to avoid a lot of needless duplicate code and keep our data structures focussed on what makes them unique: their structure. As practice I encourage you to write a few functions for our generic file structure, such as retrieving a file from a fs by the absolute path or mapping 3 functions on all 3 levels of metadata. You can find many different functions on this data structure with implementations here.

Happy coding!