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.


    Transition State based on Existing State using the State ADT

    Ian Hofmann-HicksIan Hofmann-Hicks

    While sometimes outside input can have influence on how a given stateful transaction transitions, there are many times where the current state at the time of a transaction. We can see the power of this type of transaction by seeing what it would take to read from two different locations in state in parallel and then pass on the result of combining them under a comparison operation to another transition that will set a different location based on the result.



    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 have this is correct attribute, which we would like to set to true or false depending on if the hint provided in this hint attribute matches a card selected from this cards array.

    We'll first need a way to set the value in is correct, so we pop over to our feedback model and export a new state transaction as a function called set is correct that will take in an is correct Boolean value. We'll define said is correct as a function that takes a Boolean to our beloved state app state of unit.

    To implement, we reach for this over helper, pointing at our is correct key. We'll use the crock's constant function that returns a function that always gives back the value it was loaded with. The setting is correct to the value we were called with.

    Now we should take this little bugger for a spin and see what this transaction will do for us. We need to import in set is correct from our feedback module located at data model feedback. Down in the depths of our index file, we pass our log function, the result of calling set is correct with false.

    See, we get back a state instance which we then run using exec with our initial state and observe that is correct is marked false. With true marking it is true. Now that we can set is correct, we need a function in our feedback module that validates a player's answer against the current hint. We'll call it validate answer.

    We define validate answer as a function that takes a given string to a state app state of Boolean. To implement, we reach for the crock's converge function that branches an input into two paths and merges them into one final answer.

    We'll merge our paths with a two, combing them with this equals function, comparing the results of get hint and get card. Converge passes its argument to both get hint and get card, which in our case is going to be the ID of the card the player answers with.

    To see this in action, we call an imported validated answer, passing an ID of green square and run the result with the val width to peak at the result int. With a quick save we see we get back false, even though we were expecting true. To see what could be causing this we look at the sigs for our state functions and we see get hint returns a hint while get card returns a card.

    In order to compare apples to apples, we need to convert a card to a hint, which we'll do with the helper that will call card to hint that will take an ID as its input. We define card to hint as a function that takes a string to a state app state of hint. To implement we use get card to pull our card just like before, but this time we'll map the crock's omit function that removes a list of keys from a given object, ID in our case, to convert a card to a hint.

    Now down in validate answer we just swap out get card with card to hint and observe we're getting our expected result of true. An answer of orange square gives us false and the same goes for a non-existent purple star. Now that we have a working flow, let's see about ways we can implement in a more point free style.

    First let's put back our valid answer and pop into feedback where we'll convert card to hint into a composition that maps our omit function that removes the ID from the object that resides in the result after a call to get card, which pulls the card from our cards array.

    With a little housekeeping and some nail care emoji we can clean this up to make it easier on the eyes of future us, putting each step in this composition on its own line. Future us will thank us. Popping back into index, we verify that the flow still works as expected with the false blue square and our valid green square.

    To keep cognitive low down on future us, we'll introduce this helper called lift state that takes a function A to B, then in A and returns us a state as a B. It takes a function FN and composes it with a call to state dot of, lifting the result of FN into a state instance, giving us a Kleisli arrow.

    Now that we have a means to create a Kleisli, we can change this compose into a compose K and replace this map function with our lift state, keeping it Kleisli all the way down. Again, we verify equivalents in index with a false orange square and a truthy green square.

    We now have all the pieces of our feedback puzzle. Let's put it all together by creating a feedback function, which we define as a function that takes our string ID and gives us back the all too familiar state app state of unit.

    Implementation is just using compose K to combine our two transitions sequentially by setting our is correct attribute with the result of our answer validation. With no need to expose anything else in this file, we export feedback as the default and just pop back to index, pulling the default and assigning it to feedback, which we'll use downstairs to take a peek at the resultant by swapping it with the old validate answer, getting our expected unit in the resultant.

    With a quick change to exec with, we see that we did in fact transition our state as expected with is correct set true while a false blue square sets it to false.