Everything you wanted to know about Sum Types (but were almost afraid to ask)
If the value is not valid for the kind of operation you are running on it, well, too bad. To save yourself from this, you can write run-time validations, add type-checks, etc but the core of the problem is still left largely unsolved.
Let’s learn from Haskell
Functional programming languages like Haskell have a clear solution for this. Sum Types! Sum Type (or Tagged Union) is an Algebraic Data Type which describes values that can take on several different types.
Popular examples in Haskell are the Maybe monad (for handling the validity of values) and the Either monad (for error handling).
Don’t worry. Maybe, I don’t know anything about monads Either (see, what I did there?). All we need to know is that a Sum Type has multiple named constructors.
In Haskell, a Sum type looks something like this –
Here, MetalGenre is the type and ProgMetal, DeathCore are constructors of that type.
A really popular and useful example of a Sum type in the functional world is the Maybe type. In Haskell, Maybe is a monad that wraps a value and helps you make sure that invalid values are not acted upon, thus allowing you to write safer functions.
This is what Maybe’s definition looks like in Haskell –
Now here, all valid values will be wrapped in a Just and all invalid values will be wrapped in a Nothing. This way, we can handle invalid values in a clean and elegant way and be sure of the fact that the function is only called for the valid values.
This is what the metal genre example would look like with EnumFP.
The concept of what a Maybe does is more important than the implementation itself. Containing a value in a way that allows you to perform a set of operations on the container and not worry about the validity of the input is what Maybe is about.
You can implement a simple Maybe and a couple of utility functions using EnumFP. EnumFP also allows you to add argument descriptions. This example uses the caseOf function which is like match but for partial application).
Here, fmap returns a new Maybe and runs the function over the value inside, in case of Just and ignores a Nothing. (Like Array.prototype.map) mjoin unwraps a given nested Maybe. Because many monads like Maybe, are agnostic about the value inside, you can put the monad inside another monad (That’s what she said) (Like Array.prototype.flatten) chain maps over the Maybe and then flattens the resulting nested Maybe. (Like Array.prototype.flatMap).
Let’s use this and write a function that accepts a User instance and gives you the first name without throwing an error for invalid user or invalid name.
In the example above, we first convert the user to a safe user by wrapping it in a Maybe. Then we get the user’s name using the prop function. The prop and head functions here, instead of returning the value, wraps the value in a Maybe. This is why to map it and then unwrap it, we use chain instead of fmap.
Working with React
Yes, EnumFP works well with react! (Jumping from one over-populated community to the next).
With the new react hooks being introduced in 16.7, it would be a sin not to mention it here. EnumFP ships with a useReducer hook which is a simple wrapper around react’s useReducer.
Don’t want to upgrade to 16.7? Do you still watch reruns of Seinfeld? Want to wait for your grand-children to help you with the upgrade… and… walking?
No worries. There’s an HOC available as well.
You can find out more about integrations with react here.
And this is not limited to just component state tho. You can use Sum Types to work with any kind of enumerable state values. From handling Success, Pending and Failure states for any action to containing values based on it’s type or validity. Sum Types are here to clean up all of that.