Just like the State ADT an Array is also an Applicative Functor. That means we can do the same tricks with liftA2
with Array
that we have been doing with State
. While the Applicative aspect of State
allows use to combine multiple stateful transitions over a function, Array
allows us to create a new Array
that contains the results of calling every permutation of each element in two arrays over a function. We will use this ability to pull from two separate locations in our AppState
and generate an Array
of Card
s.
Instructor: [00:00] We'll be doing three things to multiply two lists from our initial state. First, we pull our colors array, followed by pulling our shapes array. Finally, we multiply them over a combining function. Our initial state contains both arrays, a colors array and an array of shape names.
[00:16] Let's kick this off by first pulling our colors from our state. We'll jump into our game model and export a new transaction that places our colors array in our resultant, calling it getColors, taking a unit as its input. We define the getColors transaction as a function that takes a unit to a state appState of array of string.
[00:38] We implement getColors using our getState helper function, pointing at our colors array. getState will look up the colors attribute and place whatever resides there in the resultant of our state instance.
[00:50] In our index file, we import getColors by plucking it off of data model game. Then we log out the result of calling it down below to get our expected state instance ready to be run with our initial state by using evalWith to peek at the resultant, although it's not what we expect.
[01:07] We want an array of string but have a maybe of array of string due to getState returning a maybe. That's cool. We'll just option out the maybe with an empty array by mapping our state. Problem solved. That finishes up the first task and kind of solves the second because we need to do the same thing for getShapes.
[01:25] With some copypasta love, we duplicate this flow and change the name and attribute we're pointing to. Now we can pull shapes like a boss. Nice. To demonstrate, we replace getColors with getShapes up top and down below, followed by a quick save to see just how cool we are.
[01:44] Now we want to multiply these arrays over this function that takes a string to a function that takes a string to a card, called buildCard. buildCard is a curried function that accepts names for color and shape and returns an object that constructs an ID and adds the names to the object, thus giving us a card.
[02:03] To multiply, we'll take advantage of the fact that array, just like state, is an applicative functor. To demonstrate, we'll export this function that we aptly name buildCards, plural, that takes an array of string, then another array of string and gives us back an array of card.
[02:21] Implementation is as simple as applying liftA2 with buildCard ready to take two arrays of string. To prove that this does what we think it does, we import it into our index file and replace our getShapes mess with a call to buildCards, passing an array of one, two, three for the first argument and the strings A, B for the second.
[02:43] Voilà. Array multiplication at it's finest. Not convinced this is multiplication? Checking the length gives us back 2*3, or 6. Adding a fourth gives us eight. If that's not multiplication, I don't know what is.
[02:58] Moving right along, we need to get this into our state. Again, we rely on the applicative, this time for state, by exporting a function we cleverly call generateCards, which we define as a function that goes from unit to a state appState of array of card.
[03:14] We just lean on the Crocks converge combinator and lift buildCards into our state flow by partially applying it to liftA2 for our combining function.
[03:23] With getColors coming in on the left and getShapes coming in on the right, we're ready to show this off to the world, which we do by replacing buildCards with generateCards throughout our index and then promptly call it with unit to see our expected state instance. When peeking at the resultant, we see our expected results. A quick check of length is 3*4, or 12.
Awesome!