Let's consider addition. If we have 1 + 0we get back one. If we have 2 + 0we get back two. In fact if we have anything plus zero, we get back that thing.
Remember, a semigroup is a type with a concat method. If this addition is our concatenation, we have a neutral element here that acts as an identity of sorts that gives us back our element we're trying to concat with. If we have a special element like the zero here under addition, we have what's called a monoid, that is a semigroup with a special element in there that acts like a neutral identity.
Let's go ahead and define an interphase with this and we'll say sum is a monoid if it has a concat method that is it is a semigroup, and it has this empty function on it that will return us a special tag here, a special sum with the zero here, a neutral element.
Here, we can say sum.empty, and we'll concat that with the rest of it. We're programming to an interface here now, with empty and concat, not special zeroes and plusses. That shall give us our results of Sum 3, and it doesn't seem to matter that this empty is here at all, because it is a neutral element. We should still have Sum 3 without it. Good, good.
Now let's see if we can do the same with all. All has a concat method, so it is a semigroup. If we want to give it a special element, we'll make this empty function, so it can be a monoid. What would this element be? It has to be an all of something, because we want to always hold the all structure as we're combining things.
We're using the Boolean with Conjunction here to combine things. Let's go ahead see what happens. If we combine true with the false, we will get back a false that's not our X. How about a true with a true? There we go. We get back true. Good.
How about if we have the other way around, we have a false and a true? We'll get back half false. Perfect. So our X, combined with our neutral element, true, returns back our X here, just like zero. Now all, we know our neutral element is true here. So, there we go.
Now, if we have all concat true, we can make sure this stays all true there, and we can go ahead and concat all.empty. This should still all be true, and if any of these become false, it will remain false, and the empty element doesn't seem to affect anything at all. Good, good.
Finally, let's see if we can define an empty method for our first semigroup. First, we'll just throw away the second thing we're trying to combine with, and return our first. Let's see if this works. First, lets say hello, and we want to concat that with some special element that returns back our first thing. This could be anything, really.
How about the other way around? If we have some special element concated with our first hello? Does this work? No it doesn't because it's just going to throw our second part away and this first neutral element can't be defined. We just don't know how to do it.
For now without any special tricks, our first semigroup shall remain a semigroup. We cannot promote it to a monoid because we have no way to define a neutral element on here.
Let's look at one last thing. Suppose we want to write a sum function. It takes some list of Xs and we just reduce them by adding each one together and starting at zero. Would you look at that? We have the same operations as on our sum type.
Up here we have concat and our empty zero. If I call sum on a list of one, two, three, it will yield six. If I call it on an empty list, it will yield zero for empty. Let's see if we can do the same thing with all. Sure enough we have our operation here, our conjunction and we start with true.
On an empty list we will receive true, otherwise it will go through and combine each one with this combining method. Finally with our first, we have a list. We will try to take the first element of the list. We just grab the accumulator in this case and we can give it no starting value because we don't have a starting value. If we call first on a list of one, two, three, we will get back the one.
However, if it's an empty list it will blow up, and we can witness this here. I'll console.log the first of one, two, three. That should be one, and an empty list it will just blow up in our faces here because we don't have any value to return.
What can we deduce from this? A semigroup, it does not have an element to return so it's not a safe operation, whereas with the monoids we could take as many as we possibly want, even none, and still return us back something. It's a perfectly safe operation here that we can reduce as many of them as we'd like.