Maybe
This is a type with two variants. You either have Nothing
or you have Just
a value. The type variable makes it possible to have a Maybe Float
and Maybe String
depending on the particular value.
This can be handy in two main scenarios: partial functions and optional fields.
Sometimes you want a function that gives an answer for some inputs, but not others. Many people run into this with String.toFloat
when trying to convert user input into numbers. Let’s see it in action:
Try calling String.toFloat
with other strings to see what happens ⬆️
Not all strings make sense as numbers, so this function models that explicitly. Can a string be turned into a float? Maybe! From there we can pattern match on the resulting data and continue as appropriate.
For example, say we are running a social networking website. Connecting people, friendship, etc. You know the spiel. The Onion outlined our real goals best back in 2011: . And if we want all the data, we need to ease people into it. Let them add it later. Add features that encourage them to share more and more information over time.
So let’s start with a simple model of a user. They must have a name, but we are going to make the age optional.
type alias User =
, age : Maybe Int
}
Now say Sue creates an account, but decides not to provide her birthday:
Sue’s friends cannot wish her a happy birthday though. I wonder if they really care about her… Later Tom creates a profile and does give his age:
tom =
{ name = "Tom", age = Just 24 }
Great, that will be nice on his birthday. But more importantly, Tom is part of a valuable demographic! The advertisers will be pleased.
Alright, so now that we have some users, how can we market alcohol to them without breaking any laws? People would probably be mad if we market to people under 21, so let’s check for that:
Notice that the Maybe
type forces us to pattern match on the users age. It is actually impossible to write code where you forget that users may not have an age. Elm makes sure of it! Now we can advertise alcohol confident that we are not influencing minors directly! Only their older peers.
For example, say we have an exercise app where we compete against our friends. You start with a list of your friend’s names, but you can load more fitness information about them later. You might be tempted to model it like this:
{ name : String
, age : Maybe Int
, height : Maybe Float
, weight : Maybe Float
}
All the information is there, but you are not really modeling the way your particular application works. It would be much more precise to model it like this instead:
This new model is capturing much more about your application. There are only two real situations. Either you have just the name, or you have the name and a bunch of information. In your view code, you just think about whether you are showing a Less
or More
view of the friend. You do not have to answer questions like “what if I have an but not a weight
?” That is not possible with our more precise type!
Point is, if you find yourself using Maybe
everywhere, it is worth examining your type
and type alias
definitions to see if you can find a more precise representation. This often leads to a lot of nice refactors in your update and view code!