When combining multiple State
ADT instances that depend on the same input, using chain
can become quite burdensome. We end up having to play leapfrog with values inside of nested chain statements. Very reminiscent of the old callback nastiness we had to deal with before Promises
graced our existence.
But fear not, but taking advantage of the Applicative Functor portion of the State
ADT in combination with the converge
combinator, we can apply these types of transitions in unison, passing the value to both virtually simultaneously.
Instructor: [00:00] In our initial state, we define this rank attribute, which we would like to either decrement or increment based on the value isCorrect is set with. We set isCorrect based on this hint object being equal to a card picked from this cards array.
[00:14] Inside of our feedback model, we've defined this adjustRank function that takes a Boolean to a function that takes a number to a number. adjustRank is a composition that employs this decOrInc helper that is a function defined as a function that takes a Boolean to another function that takes a number to a number.
[00:33] When the Boolean is true, it returns the dec helper to decrement a value, or it returns inc to increment. The chosen function is then passed to limitRank, which limits the result to a value between zero and four.
[00:46] To see how we can use this function to update our rank based on a Boolean value, we'll create this updateRank transition that takes a Boolean isCorrect as its input. We define updateRank as a function that takes a Boolean to a state, appState of unit.
[01:04] To implement, we use our over function that runs over our rank with the adjustRank function, which we prime with our input, isCorrect. To get a feel for what the heck this thing is even doing, let's pop over to our humble index file and import it in for a little play time.
[01:21] We pull updateRank off of our module that is located at data model feedback, tossing in a quick save to ensure our pathing is correct. We pass the result of calling it with the value of true to our log function and see we get back a new state instance.
[01:37] When run with execWith on our initial state, we find the rank decremented to three. By updating the rank to a value of two, we see it is now one. When we call updateRank with false, we observe that it increments a two to a three. If we start with a rank of four, we find our rank limited to four.
[01:57] If we look at some of the [inaudible] in our feedback model, we see that updateRank takes a Boolean. We have setIsCorrect that also takes a Boolean. We also have a function validateAnswer that will return a Boolean in the resultant.
[02:12] Using the converge function from Crocks, we can split the result of validateAnswer to both updateRank and setIsCorrect, calling this function applyFeedback. With converge, we merge using liftA2 to combine our transitions and load it with constant, which returns the unit from our left portion.
[02:31] We branch our Boolean between setIsCorrect in the left and updateRank on the right, giving us back a new state instance that will apply our transitions, throwing the unit from setIsCorrect in the resultant. To get this into our feedback flow, it's just a matter of replacing setIsCorrect with our spick-and-span applyFeedback, followed by a quick sanity save.
[02:54] Over in our index file, we can do nothing with feedback until we import it in. We pull it off the default on our feedback module. Then popping down to our log function, we swap out updateRank with feedback, calling it with the correct answer of green-square, saving it down to see isCorrect set in addition to our rank being decremented.
[03:16] Starting with a rank of two, we get rank set to one. If we answer with an incorrect blue triangle, we find isCorrect false and our rank incremented to three. However, starting with a rank of four, we never exceed four.