Check out a free preview of the full Hardcore Functional Architecture Patterns in JavaScript course
The "Monoid Solutions" 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 live codes the solutions to the monoid exercises.
Transcript from the "Monoid Solutions" Lesson
[00:00:00]
>> Okay, let's get through these together. We're in this together y'all. So, once I bring you all over to the dark side, we all have to know how to do this together so we can convince others that it's good. So there's this. I wanted to call out lists from immutable Js it does not have foldMap.
[00:00:23]
So we're using immutable extensions, which is just I took a mutable and added foldMap to it. But there's like 50 different libraries that implement it exactly the same way. So we're just using this one just to demonstrate it, but you saw, it's just reduce and you just pass in the type.
[00:00:40]
Okay, so it says to re implement some using fold map and the sum monoid. Okay, let's use foldMap here. So we have list of x's and we're going to hit instead of calling this accumulator and the x 0, we'll start with the Sum(0), or how about just Sum.empty?
[00:00:59]
And Pass in Sum and foldMap. So we're gonna take this list of xs, turn them into sums, starting with empty. Now, since xs, there's actually stuff there, it's not gonna break if I don't. No, I guess it is gonna break, all right, that's fine. [LAUGH] I've updated the library so it works more like reduce.
[00:01:19]
It doesn't break if it's not there, but It should be there, so deal with it. But foldMap can work on semigroups, it's just an unsafe operation. So there's that one, any questions on that? Did anybody have any struggles? And maybe this was a little too ambiguous.
>> [LAUGH] All right, great question.
[00:01:44]
How does this work, exactly? So what's happening is, we have this 123, right? What's going on with foldMap actually is. Let's let's go ahead and write foldMap in a different way. FoldMap takes a type, right? Let's call that t so we don't have some weird like your keyword air and a bunch of x's.
[00:02:08]
We'll say xs reduce will take you accumulator and each x, and we're gonna put was this it takes actually three arguments. This first one, we're gonna push over here, right? So it's t then of empty, all right, and the x's. So we can start with empty here as our initial accumulator will just do aq concat x.
[00:02:35]
So this is how foldMap is implemented under the hood, it's just a reduce. So what's happening here is if we go ahead and stead and call foldMap, some some of the empty and our xs that should hopefully still pass. We get a Nan, Nan. How's that looking? We got this type some, which is t I didn't put it in the t.
[00:03:01]
That's the that's kind of the crux of this right is that and now it's passing is that when we say foldMap, we're saying we want to fold this list down 123. But first we want to map it into the subtype, that's this map, proportion, a portion here. So we could alternatively instead of putting the t here, we could actually say, first map, put it in the type, then reduce it down just by calling concat on everything, and we still pass.
[00:03:29]
So this is kind of how it works under the hood. If we go back to the other syntax where we've just got a list of xs and we're going to foldMap that into a sum. We can expand this by saying we've got each x and we're gonna put that in the sum type and then it just knows how to combine them all.
[00:03:49]
So there is another function that it didn't mention which is just full. So let's say I have and it ticks an empty. Let's say I have a list and we map over it and we put that into a sum and we just fold down that list. FoldMap is just first map it then fold it, fold being this this part where we just concat everything.
[00:04:12]
So, that's where the name fold map comes from. Fold is just concat everything into my list because everything in my list has a concat method. And we would just end up with one thing, we fold the structure down into one value. And fold and map are not specialized to list.
[00:04:31]
We can do this on trees, we can do this on events stream, we can do this on many different data structures that hold collections even either you would be able to fold map it out of the either, right? So foldMap is very useful, fold is very useful. Its from an interface called foldable and if we have monoids and semi groups at our disposal, its one of the most useful methods in functional programming.
[00:05:03]
Okay, let's move on. I hope that answered your question, did it a little bit more, okay.
>> This may be an implementation issue with lists, but I got hung up trying to pass xs to list.of.
>> Yes, so that's great. So Mutable JS does create pointers functions. And I could say a list of two, and that would put me in a list.
[00:05:30]
But if I said list of an array of two, that would put a list of a list of two. We're lifting that in. And if I just call a list of two, it's like, hey, you're not an array so, this would work for that case, this would work for this case.
[00:05:49]
So this one's coercing it's kind of a bunch of is kind of probably the the proper way. It's just down here, I have a list, passing into it. So cool. Anything less than zero or any less than zero. So this says, okay, we're trying to program the foldMap and we're trying to see, some of its utility here like this.
[00:06:12]
These examples are kinda toy examples, getting the ergonomics around how to call foldMap and put things into types and take them out. But when you start to do some of the architectural stuff, and we'll see some examples following this and build a little library, what happens here is that the types cascade, right?
[00:06:33]
So you're actually combining effects and values and making branching decisions and doing all this really intense computation with a full foldMap and it's capturing it intuitively. So these are really small, easy examples, but you can imagine this is like I've got a list of Async, error, filled, like whatever decision making values and then we kinda go down the right path.
[00:07:00]
So let's go ahead and write foldMap here. And just like before, we're just gonna do foldMap any, and any.empty, does that work? It does work. What happened there? You get negative two. What is that? This is less than zero, sorry my bad. It says re-implemented that using the any mono-id.
[00:07:25]
Okay, that's fine. We're fine. So a fold Map and if this is less than zero, we're gonna return true, all right. Any true. There we go. Otherwise any false and we'll start with any empty. How does that go? All right now it's passing you see how that works.
[00:07:48]
I got confused because I was just following my template without thinking. But the idea is that any doesn't take a zero It takes a number. It takes a Boolean so we can do our Boolean, then return the any. And then I'll just combine all of them.
>> Just to make sure that I'm not making a naive technical switch in my own code.
[00:08:05]
I put a lambda function in and then passed in any with x less than zero and that also comes through. That checks but architecturally.
>> Anything.
>> I did the comparison inside of one any.
>> Like that?
>> Getting there but you just used the x not the accumulator.
[00:08:27]
>> Just using.
>> Yeah, if you take out the accumulator, put x less than 0. And then take out anything after the question mark, because that's implicit in that operation. Is that, that is passing, but am I changing anything? I think you've got to take out an ACC thank you.
[00:08:49]
That's right. Thank you. That's right, foldMap doesn't take in. Sorry, I had this wrong, foldMap doesn't take an accumulator, right? The accumulator is now gone. So it's just going to hold that accumulator in the background. All you're concerned about here is just keeping one. So this is actually a much simpler way to write the same thing, thank you.
[00:09:08]
>> Okay, thank you.
>> So what we're doing is saying. I need to take a list of numbers and turn them into a list of entities and to turn them into a list I'm given a function and now I have a list of entities, anything less than zero, cool.
[00:09:21]
>> I did it a little bit differently too, I called map first to turn the numbers into Bolivians Cool, and then called fold map to put the Booleans in
>> Yeah, sounds great. So something like this where you map each x, and say x less than zero. So another trues and falses, and give you any here.
[00:09:40]
Yeah, that's nice. It's good way to do that. You could also do any here and then just fold it down. And so foldMap just combines the folder and the map into one thing for efficiency when it almost never matters. [LAUGH] Sorry I'm never gonna stop saying that [LAUGH].
[00:10:04]
Okay, so let's do this. We have the max. So there's two more left here we'll get through these, max is pretty sweet monoid. We can actually look at this one yet, but we start with negative infinity. My favorite value and we say, all right, well, the accumulator greater than x or not.
[00:10:27]
So it says rewrite it with a max monoid. And it says it says to actually make a max monoid using these templates above. I'm just going to copy this, bring it down here into this part. Did anybody get this one? This one's a little bit tricky. Didn't really feel like they got stuck on the shortcut.
[00:10:46]
It’s really just a matter of swapping out this operator with the max operator. We don’t need the, I guess we can do the max x negative infinity, right? So that’s the empty value over here corresponding with the second argument. This is corresponding to the first argument where we're saying is it greater than x or actually looks like this is what we need to do.
[00:11:10]
We can just grab in. We'd say, A, is x greater than o x? Well, then we'll keep x. Otherwise we'll keep o x. Meaning the other other Mac's that we're trying to compare to. And then we'll go ahead and rewrite this as a foldMmap with Max and Max, empty passing.
[00:11:36]
Yeah, we're passing. So, questions on this one? This one's a little bit you know, you're making a monoid kind of following the pattern above but this was a little different, right? I was initially like, let's swap out the operator but that's not how it works. You're making a choice here you have to choose one or the other.
[00:11:56]
So the greater than or less than just give me a Boolean, and so I would have had a problem. Finally, we're gonna write concat here for tuple or tuple however, you say it. And this one's kinda cool. Just like we said functors and other, actually, this is a functor if we write map on it, which tap to pick one to map over.
[00:12:21]
It's bi-functor if you want to map over both. But the point is, we want to make tuple as a type into a monoid or semi-group by giving it a concat method. So if I have another tuple. I could say one concat well concat my one with 0.1 right?
[00:12:47]
We'll keep it in the table. It's always closed, right? And then we have my to look at it concat it with the other ones. Two and fine, I'm okay. Code pen you don't have to warn me, got it. [LAUGH] I feel ike a surly teenager and Code pen is my parent.
[00:13:08]
So this is how that works, we're saying, I'm holding two values. And if I can concat everything I'm holding, then I, myself can be concated. And that just awaits holds, so I have a type that's entirely built of concatable things, I can just concat all the stuff I'm holding and there we are.
[00:13:30]
So now I can put anything into a tuple or a tuple. I haven't fixed which way I'm gonna say it yet. So both [LAUGH] which is ironic because it holds two things.
Learn Straight from the Experts Who Shape the Modern Web
- In-depth Courses
- Industry Leading Experts
- Learning Paths
- Live Interactive Workshops