Instructor: We start with these two attributes in our state -- left to keep track of the moves a player has left, and moves, which tracks the number of moves a player has taken. We also have these two state transitions -- decLeft, that decrements the moves left, and incMoves, that increments the moves taken, which we've defined here in our answer model.
Back in our index file, we can log our call to decLeft, passing it unit as its input. We see we get back a state instance. To run our state, we call exitWith, passing our initial state, which decrements our left attribute.
To marry these transactions into one transactions, we chain in incMoves to apply it. Now, both transitions are applied to our initial state. We can now create a single transaction that can be exported from our answer model, which will be a function that we'll call applyMove.
ApplyMove is defined as a function that goes from a unit to state, app state of unit. To implement, we take in our unit, and mimic what we did before, calling decLeft with unit, and then chaining in incMoves.
After a quick save, we can jump back into index and replace the two functions endports with one applyMove. Now, we just get rid of the old crusties downstairs, and replace with the hot, new applyMove, call it with unit.
We now have one sole transaction that can easily be chained not only once, but as many times as our wee hearts desire, without fear of stepping outside of our defined range, due to our previously implemented clamping function.
After we reset our index, let's jump back into our answer model and take a look at this transaction. If we look at the siggy for incMoves, we see that it's a Kleisli arrow that maps unit to unit. Upstairs, we see that decLeft is also the same Kleisli, which means we can do Kleisli composition on these functions.
We can replace this fluent style with composeK, which will give us a new Kleisli that calls incMoves after decLeft, matching what we had before. Well, once we axe this bit, of course, and give it a save. We see they are equivalent.
We should also verify that chaining still works as expected. Chaining one still works, and so does chaining many. As we want these to always change together, we could remove the exports and only provide applyMove.
That way, we keep our model concerns in the model, and not have them leak out to other parts of our app.