We'll examine how to unnest function calls, capture assignment, and create a linear data flow with a type we call Box. This is our introduction to working with the various container-style types.
What are we looking at here? We have next [inaudible 0:03] our number string. What this does is take a string down here like our number. We could have spaces, comes with user input or whatever. We're going to trim it, parse int, add one number to it, and get the char code from string.
The point of this function is not the actual functionality. If you look at each of these lines, they're doing different things. We have a method call here. We have a function call here, an operator, and then a qualified class function here. We want to unify it all and compose it in one linear work flow instead of separate lines with lots of assignment and state as we go along.
How can we do this? Let's run it to see what the output is. It's the capital A. That's because 64 turns into 65, then we get the char code of that which is the capital A.
If we comment this out, and let's rewrite this in a new way, one thing we can do is say we'll try to compose this up in one big expression functionality. We'll call trim which is the method. The next thing that happens is we parse the int. The next thing that happens is we add a one. We call string from char code around it.
This is very confusing. It will still work. Let's give it a shot. There it does. It's got a capital A there. If we look at the control flow here, it's totally bogus. It's one expression, very clean, but hard to follow. It jumps all around here, trimming, parsing, and adding one over there.
Let's borrow a trick from our friend array. The first thing we can do is put our string in a box, and that's it. We put the string in a box. It's just an array with one value.
Now, we can map our S and trim it. We can keep chaining these maps. We can turn this S into a number by calling parseInt on it. What do we have? We have an I here for an int. We can say I plus one.
Finally, we'll say I is string from char code. We turn that back into a number. This is very, very nice letter rather. If we run this, we should have A in a box. Indeed, we do. We have A in the array. I'm calling it a box here.
What happened here? We've captured each assignment in a very minimal context. S cannot be used outside of this little error function in map. Despite calling it the same variable here, we can change this to R or whatever we want to call it.
The point is, each expression has its own state completely contained. We can break up our work flow, and go top to bottom, doing one thing at a time, composing together. That's key. Map is composition, because it takes input to output and passes it along to the next map. We're composing this way.
Let's see what else we can do here. Instead of an array with a bunch of maps on it, why don't we make this a little bit more formal? I'm going to make a type called box. Box is going to take an X here. We'll define a map of our own that works exactly the same way.
We'll take some function F. It will return a box of F of X. It's returning a box of F of X, so we can keep chaining along. If we didn't return the box, we wouldn't be able to call .NET, .NET again and again.
We're running our function with F on X, and then putting it back in a box. This should be exactly the same thing. We could put this in a box and have this work flow happen here.
Let's do one more thing, though. Because it's hard to look at this data structure in the output, let's give it a little inspect. This is a nice little trick that allows us to, when we call console.log, we actually see what the data structure is holding and not just the data structure itself.
It will format the output and the little template there earlier. We need a little comma, and let's give it a go and see if we have ourselves a box of A. Indeed, we do, a box of A. That's very good.
With this, we can start composing along. We've unified both method calls, function calls, operators, and qualified. We can start parsing int here. We can do a constructor for new number, and so on and so forth.
If we want to add more functions, we can go ahead and map along, and say maybe I, or what is this? It's a char code now. It's a C here. We'll say C, too, in our case. Now, we have a lower case A in a box.
What to do with this box? We didn't actually want it in our box. We wanted it outside of the box. We wanted our normal character here. Let's add one more function at the box. We'll call it fold. What this will do is remove it from the box as we run the functions just like map, except it doesn't put it back in the box.
Down here on our last statement, we can call fold instead of map, which will fold it out. It will remove it from the box as it runs this function. Does anybody have any questions?
I thought map was supposed to loop over stuff?
Map isn't so much about iteration as we'll see. It has more to do with composition within a context. In this case, box is our context. We're going to be using a lot of these container-y types to capture different behaviors as we compose. It allows us to compose in different ways.
Isn't that the identity factor?
Indeed, it is the identity factor, but we're going to call it box for now so we don't scare everyone.
That can't be efficient.
As far as efficiency is concerned, because this is composition in disguise, we confuse this together. As it stands, you'd be hard-pressed to tell any difference at all even in the large-scale application doing all these things unless you are making a pacemaker, doing a bench mark of 10,000 or something like that.