REASON Variant
As the Reason-ml docs say, Variants are the crown jewel of the language.
https://reasonml.github.io/docs/en/variantYou may have noticed something in the earlier example when we were looking at optional arguments in functions.
To recall, here's the function again.
```reason
let toString = (~name, ~age=?,()) => {
switch age {
| None => "The User's name is " ++ name ++ ""
| Some(agevalue) => "The User's name is " ++ name ++ " and his age is" ++ string_of_int(agevalue)
};
}
```
Variant data type is also called tagged union. A tag field eg (`None` or `Some(a)`) explicitly shows which one is in use at a particular time.
On putting things into context. Its either the age is present or it isn't. It cannot be both present and not present at the same time.
The two commonly used built in variants.
OptionList
The option variant has the following signature
```reason
type option('a) =
| None
| Some('a)
```
`option` takes a a type as an argument
as we can recall in the first lesson on types.
Lets assume we want a Facebook profile URL for a user, but keeping in mind that the user may or may not have an account with Facebook.
```reason
type faceBookProfileUrl = option(string)
let fburl: faceBookProfileUrl = None;
let resolveUrl = switch fburl {
| None => "Sorry This user does't have an account"
| Some(url) =>"The user's facebook profile Url is " ++ url
};
```
So we are using pattern matching again to match based on the Tags of `option` data type.
Type arguments help enforce help enforce strict rules on the types. For instance the below code will bring errors.
```reason
let fburl: faceBookProfileUrl = Some(12);
```
This is because faceBookProfileUrl expects either None or Some of type string.
On fixing that we can have
```reason
let fburl: faceBookProfileUrl = Some("https://www.facebook.com/Studytonight/");
```
As we saw earlier when pattern matching on a list with the recursive function sum
a list is either empty [] or has a head and tail.
```reason
let rec sum = lst => {
switch lst {
| [] => 0
| [hd, ...tl] => hd + sum(tl)
};
}
```
The list variant can look like this
```reason
type list('a) = Empty | Head('a, list('a));
```
We will discuss this later when we finally talk about pattern matching, for now just know that a list can either be empty or have a head and a tail.
Building Our Own Variants
Say we want to create a small schedule and do certain tasks based on which day it is.
We can create a variant the days of the week.
```reason
type days =
| Sun
| Mon
| Tue
| Wed
| Thur
| Fri
| Sat
```
Now that we have our variant and all its tags.
I can now create our schedule function
```reason
let schedule = day => switch day {
| Sun => "Relax and chill"
| Mon => "Sleep on your way to work"
| Tue => "Go out for a movie"
| Wed => "Learn a new Skill"
| Thur => "Run in the morning"
| Fri => "Plan for the following week"
| Sat => "Run in the evening"
};
```
Our schedule is all set now.
When working with variants, the compiler will warn you if you leave out a certain tag.
Try deleting any tag from the schedule function to see for yourself.
Okay, first week things went well but we wanted to be more strict with ourselves and accurately define our goals of the week.
For instance if we were to run we want to see how many miles we are to run.
Tag/Constructor Arguments
Fortunately, Tags can take arguments.
We can refactor the `Thur` tag to take an int which will represent the miles we are to run like so
```reason
Thur(int)
```
and on the schedule we can replace the `Thur` tag with
```reason
Thur(miles) => "Run in the morning for " ++ string_of_int(miles) ++ " miles"
```
Note
`string_of_int` converts an int to a string so that we can con-cat it with the other strings.
With this you know have a solid understanding of variants, next up will shall look at Pattern Matching in depth.