Check out a free preview of the full Hardcore Functional Architecture Patterns in JavaScript course

The "Concat Method" Lesson is part of the full, Hardcore Functional Architecture Patterns in JavaScript course featured in this preview video. Here's what you'd learn in this lesson:

Brian demonstrates how to concat different functors together, and how to use the concat method to join different monoids.


Transcript from the "Concat Method" Lesson

>> Let's just quickly look at what it looks like to concat a couple of functors together. So if I have a write of Hello, concat it with array of world. I shall have rows that fold log console.log. I should have a write of or I will just get hello world because I'm folding it out.

But what it is is actually a write of Hello world. Does everybody see that? What if I have a left of ahhhrgghghhhh [LAUGH]. Does anybody have a guess of what's gonna happen here given either's behaviour?
>> Just to get a left.
>> That's right. It will short circuit everything.

If you hit a left anywhere in this giant associative concat, if we're gonna fold a giant list of left's or rights a bunch of ethers. If you hit a left, it's just going to return that as an error like, we got an error we better tell you. So let's see that.

I got our. So that's pretty neat. We can do this with task, right, task of Hello cat task of, cruel world. And then we can forge that. And then we'll still get in parallel in, we're saying we have two tasks. They're both running, they're both gonna finish. They're both doing a sync things and when you're done, concat the results.

What if we put that in an array instead of concating the string. You can concat the array inside the task, right? So that gives us different behavior. But it's still concating and so then we can, we have a right of an array and we have a left or whatever.

If we have a rejected task. Rejected, it acts like left. So if any of the tasks fail, oops, these aren't the same data type and that's fine because this is a different output should just give you the error on the task if you have a rejected task. So that way if you're out there running a bunch of a sync stuff and one of them fails, you'll get that back as the the answer.

It won't concat, so very much like right or left behavior there. There's more but I want to stop here for any questions on what we're doing. [LAUGH] yeah.
>> Is this the same behavior promise.all, where we have a single failure in the chain and the result is just, it's discarded.

>> That's right, if we have a single failure now, we'll talk about what to do here in a second. I'll do that next. If we want to be a little bit more lenient on that. But, that is exactly and it's kind of interesting. If you think about promise.all, you're saying I have a bunch of promises that are running in a list.

And really what I want at the end is, instead of a list of promises, a promise of a list, and we can think of that in terms of traversable. We could say like flip the list on the outside of the promise or vice versa. And there we go, we get a bunch of results in one promise instead of a list of a bunch of promises.

Here, we're saying, I want to actually fold all those down. I wanna take this list of promises and I wanna combine them all and it's the same exact effect. So what's happening here is, but it's a little bit more powerful, right? Because we're not just gonna get a list and we're gonna concat them however we see fit.

So you can frame your problem in terms of monads, almost always, it's like the closest thing to a silver bullet in functional programming as you can get. To quote Chris Penner [LAUGH]. So let's attack that case of, all right, I'm programming. I'm gonna combine a bunch of stuff.

And while I'm combining, I would rather, let's see, we're reading a bunch of files. And all my files I want to, if one is missing and it blows up, I just want to discard it, right? So we can say, we have our try catch here that returns us the read file sync or whatever.

And this is gonna return us a right or left. And I don't want it to just short circuit it if I'm reading a whole bunch of files and I'm concting all their contents, I don't want it to just stop if I hit an error. I just want it to be graceful and just forget about it.

That's graceful but, [LAUGH] forget about it. So let's go ahead and do this. Let's say, well, instead of right combining with another right or left, there you go and give me a left or buy. I'm gonna, I want to keep the right. So we can do this a couple different ways.

There's an interface called alternative the captures choice. Mono is capture choice, right? You can say maximum right is a monoid, where you can keep one or the other identity being infinity or negative infinity. But the idea of the interface of alternative is that we're gonna choose this or that one.

But we can do this with semigroups by saying or monoids by saying, let's just make, let's just wrap it in another type, let's call it alternative. All right, so we have this alternative. And this is gonna be holding an either x not just an x, all right. The jewel is called ex to remind us, and we'll concat that by saying, all right, well, let's just cheat.

If it is the left, I know they have that function on my either class. We will end up keeping the other one or I guess us. Because if we are left and they are left, it really doesn't matter which left we keep, right? We're just gonna keep the first one, so skip ourselves.

So, are we, can keep, oops, this is other. So if the other one is left, let's just keep ourselves otherwise, we're going to say let's say ex.concat other.ex, put that all into inside an alternative, right? Because we can't ever, it's closed, we shouldn't ever escape in a concat.

That's the first thing you should do. Whenever you're ready to concat functions, make sure you're not falling out of the type, because that is error, like what just happened. So let me see if my logic is correct. If we've got a left over here, we're gonna keep it.

It does, we're gonna keep ourselves. Otherwise, we're going to concat the insides. Now we can actually decide whether or not to concat the insides of the two or just keep the outer one, right, we can keep the first success. So these are choices that are still satisfy the interface.

But in keeping with the kind of intuition of these functor monoids, we're gonna concat the insides of the two. See if I get this right, I may not have, if anybody sees any problems shout it out. We got off the program it's a anybody's guess. So get this x out of there and folde ID, all right.

Add by blue where we got can't read is left of the other one. That's because I don't have an alternative here, to alternative All right, so, how's that? Okay, so it keeps the high, cool. What if I concat an alternative of this with concat an alternative? Another bunch of explanations.

Now concat at that with the by, hey, did it, right. And so every, it just ignores the left here it doesn't, it doesn't do anything, which is nice. So if we're taking advantage of these kind of like this cascading kind of nesting, where everything concats down, at some point in the nesting you can say, you know what, I'm not going to continue to concat inward and be a nice nested citizen.

I'm going to make a decision here and choose one or the other kind of branch my code effectively. Or I can do both as we're doing here, we're only going to concat the inside if it's a right. I want to rewrite this as a fold map real quick and then we'll jump into some exercises and we'll come back and build a little validation library.

But, yeah, so I want you to get some more experience with full map here. Turns out, this is a lot of code, right? It's kind of annoying. So what we could do is, I'm gonna go ahead and put this into a list. They have my list don't get from the first thing and just import it, okay?

So we'll have a list of Hi. And how would just a, b,c. And what we're gonna do is put those I guess we can't do that. We have to do a right a, right b, and a right of c, okay, left of c. And now we'll just go ahead and foldMap into alternative and we can choose just like reduce to ignore the initial value.

But oftentimes at the calling site, you know what the initial value is. So you want to keep it safe and provide initial value. So my initial value, if I have a bunch of strings my empty element is an empty string. And either my empty element is a right and or I guess my neutral and then alternative holding that.

So we'll fold map all these into an alternative and then hopefully this will work. And we got a and b, it concats the insides, hooray. It works. If I make this left here, we'll get a and c. So you'll end up actually making your own monoids quite a bit.

But the idea is that you'll end up making your own monoids a lot more than you are gonna make your own fanctors and such. So there, it's good to know how to make these things. And of course you can make it with a class. You don't have to make it in these little functions, you can make it more efficient or whatever.

There's a dozen ways to do it. Okay, so let's go to.
>> Following your pattern you would make like an MD and that would be a right?
>> That, yeah, you'd create a, if you want to make a monoid you have to have concat. And for semigroup, you just have to define a concat method empty is like a class method usually, because why would you have an instance if it is an instance of that class.

So usually that's why I'm kind of putting empty on the class itself. So that way it gives me my initial value of whatever. So there we go.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now