Many times we need to access and transform state, either in part or in full, to be used when calculating other state transitions. We will look at how we can leverage the get
function on the State ADT to read and modify portions of our application state, putting the result in the Resultant portion. We will create two transactions: one to select a card from a list of cards and another to access the hint portion of our state.
Instructor: [00:00] We would like to be able to read from a couple attributes in our state. We have both a cards attribute, which is an array of card objects, and this hint key, containing a hint object.
[00:10] To capture the pattern of reading from a specific location in our state, we'll reach for this getState helper, defined as a function that takes a string to a state object of maybe of any type A.
[00:23] It takes in this key as its input and uses it to prime this prop function which returns a just instance of maybe if the key exists. In turn, this function is passed to get, which applies the state to our function, placing the value of our target key in the resultant, wrapped in a maybe
[00:40] To see this convenient helper in action, we pop to the bottom of our feedback model and export a new function called getHint that takes no arguments. We can define our hot new state transition getHint as a function that takes a unit to a state appState of hint, where hint is an object with the key's color and shape and no mention of maybe.
[01:04] We implement by reaching for getState, providing it with our target of hint. Now we just need to import this into our index file and see what we got. Up in the attic of our index file, we plug getHint from our feedback module, which resides at data model feedback.
[01:23] After a quick save, we leap down into the basement of index and call our logging function, with the result of calling getHint with no arguments, getting back a new state instance, which we then run using evalWith on our state to get a peek at the resultant.
[01:38] We would like to have a hint object, but we have a hint object wrapped in a maybe. Because the value is now in the resultant, we can use map to option out our maybe to a reasonable default, which matches the hint shape, but with unknown values in both the color and shape keys.
[01:56] With a quick save, we now finally get the hint. If something goes awry and we have no hint, we get an object back we can work with. We can go about accessing the cards in the same way, but let's up the ante. Instead of pulling the entire array, let's say we look for a specific card by ID and return that instead.
[02:16] We call this transaction getCard and have it take an ID as its input. We define getCard as a function that takes a string to a state appState of card, again with no mention of maybe. A card object has the same shape as hint, except with an ID attribute. We start our implementation by again using getState, but this time pointed at cards.
[02:40] Meanwhile, back at our index file, we update our import to pull in getCard and head downstairs to replace getHint with getCard, passing it a valid ID of green-square. With a little save action, we see our maybe-wrapped cards array.
[02:57] With our maybe array in the resultant, we can do our lookup by reaching for the Crocks find function, which also returns a maybe, so we can chain it. We pass find this propEquals function that returns true when the ID matches our target, as we see here with our green-square object wrapped in a just.
[03:15] Find will return the first found value matching its predicate, wrapped in a just, like with an orange square or a nothing if nothing matches, as we see with this purple square. Just like with getHint, we care not for the maybe in our final result.
[03:30] We'll do the same thing and option it out to a reasonable default with unknown values for shape and color and also include the ID we were given. Instead of a nothing, we get back our option value, but a valid green square gives us our valid green square card.