To start off, let's first introduce our starring cast. We have three functions to play with, starting with add10 which takes a number to a number. We pass it any number and it adds 10 returning the result.
Next up is square which also takes a number to a number, but it will take the number it receives and square it instead. Finally, we have doMath which forms a composition of the two. Our data is piped through these functions right to left, and then returns the result.
Let's take these for a spin and see how they drive. Using this log function, we'll just call doMath passing it 0, and give it a save.
Let's take a gander at how we arrived at 100. 0 was passed into add 10, passing 10 onto square, which of course gets us our hundo. By passing in 1, we get the expected 121. While this works when we have numbers, by passing in this little kitty cat we find that our flow is not very purr-fect.
This is because our functions work only with numbers, so we need to deal with that constraint. Luckily, we have isValid, which will only return true when passed a finite number. One way to solve our issue, is to use isValid directly in our function, passing in our input. If we're good, we perform the computation, or we just return our value if not. This is now required in every function dependent on this value, and future us will be super mad at current us if we actually did this.
As it turns out, we can make everyone happy here by using a maybe. To start, we need a way to list a given value into a maybe based on some condition. To do this, we'll create a function called maybe. Maybe is defined as a function with two parameters.
First, it takes a predicate that we'll use to decide how to construct the maybe. Then it takes a value of any type that could be valid, and finally, it returns us a maybe of A. To implement this, we first take our predicate and return a function that accepts a value X.
Now we test our value by running it through pred. If it passes, we return an array housing our value. Otherwise, we return an empty array. Now we just expose this abomination to the world, and see what shenanigans we can get up to.
We gain access to our newly created maybe function by plucking it off this conveniently available maybe object with some destructuring. Now we create a function named maybeValid that is specific to what we want to guard for.
We will define maybeValid as a function that will take any type splat as its input, and return us a maybe of our desired number. To implement, all we need to do is apply the isValid predicate to maybe.
Meow we're ready to test this out on our kitty. We just replace doMath with maybeValid, give it a save. We see we get back our nothing. But if we pass a 0, we get an array of 0, or just 0. A 1 will get us just 1, and a valid 10 arrives at just 10. While this is great, our functions work with numbers not maybes of numbers.
We need a way to lift our functions into our maybes so they can be applied to our numbers. To do this, we'll create another maybe function called mapMaybe. mapMaybe is defined as a function that takes a function from A to B, then expects a maybe of A and after applying our function, returns us a brand new maybe of B.
To implement this, first we take a function FN and return a function ready to take our maybe M. Because we're using an array, we just apply our function to the array's built-in map, returning the result.
Like our maybe function, we just expose this function by exporting it from our module. To put it to good use, we pop to the top of our index file and just pluck it off of our maybe namespace.
Now it's time to add a little safety to our flow. To do this, we'll create a little function called safeMath which we'll use to lift our doMath function into our newfound maybe. We define safeMath as a function that will take anything A and kick us back our desired maybe of number.
The implementation is just a composition that will first run our value through maybeValid, returning a maybe, that then gets passed to mapMaybe, which we partially applied doMath to. Let's give it a shot by replacing maybeValid with safeMath, passing in 10 to get just 400. 1 gets us our just 121, and 0 will of course still gets our hundo.
Any invalid value returns us a nothing, as we see here with NaN or with an object. As long as we're in a maybe, our functions will only be applied to values that we deem valid. Now we can extend our flows with confidence.
Let's set up a composition with the ridiculously long name safeStringMath. Similar to safeMath, we can define safeStringMath as a function that takes any value A, but returns us a maybe of string instead. To get our maybeString, we extend safeMath with a composition that will use mapMaybe to lift and apply this stringify helper to the resulting maybe number that is returned from our safeMath function. Stringify takes any value and returns a string representation.
Mapping our maybeNumber to the desired maybeString. To verify our object still returns a nothing, we just pass it to safeStringMath and give it a save. But when we pass a number, we now get back a maybe of string. Passing 21 gets us 961, 0 still gets us our hundo, and 121 is the result of 1, except they are all strings still wrapped in a maybe. Eventually, we'll have to leave the safety and comfort of maybe and jump back into simple values.
To do this, we can create another function called optionMaybe. We'll define our optionMaybe as a function that will take any type A returning another function that takes a maybe of A, giving us an A.
To implement, we first take our default def and our maybe M. Then we check the length of M to determine if we're a nothing or a just. A just returns the extracted value, and nothing returns our default. Let's expose our option function and see what this looks like in practice.
Like our other maybe functions, we just pluck it off of our maybe namespace for use in our file. Now, to work this into our current flow, we'll create another composition which we'll call stringMath. stringMath is defined as a function that will take any value A, and return us a [inaudible 6:48] string regardless of our input. We implement with yet another composition that will option our maybe with a default string of none, acting on the maybe that is returned from safeStringMath.
Now with a little swaperoo, we can replace safeStringMath with stringMath. Give it a save, and observe our string of 121. Passing in 0 gives us our hundo string, and 10 arrives at our string of 400. But passing in an invalid happy cat will safely default to none.