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 =
String
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 =
Folder
(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 =
String
type File metadata
= File String metadata
type Folder folderMetadata fileMetadata
= Folder
(Dict.Dict Name (File fileMetadata))
(Dict.Dict Name (Folder folderMetadata fileMetadata))
folderMetadata
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!