Join egghead, unlock knowledge.

Want more egghead?

This lesson is for members. Join us? Get access to all 3,000+ tutorials + a community with expert developers around the world.

Unlock This Lesson
Become a member
to unlock all features

Level Up!

Access all courses & lessons on egghead today and lock-in your price for life.


    Combine Multiple State ADT Instances with the Same Input

    Ian Hofmann-HicksIan Hofmann-Hicks

    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.



    Become a Member to view code

    You must be a Member to view code

    Access all courses and lessons, track your progress, gain confidence and expertise.

    Become a Member
    and unlock code for this lesson




    Instructor: 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.

    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.

    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.

    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.

    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.

    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.

    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.

    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.

    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.

    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.

    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.

    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.