# A curated collection of Monoids and their uses

A gallery of monoid definitions and some use cases Sean Omlor
~ 4 years ago

Having trouble with the foldMap over the stats List.of. Getting `acc.concat is not a function`, any ideas? Here's my code: http://bit.ly/2hqhXZ8 Brian Lonsdorf(instructor)
~ 4 years ago

Posted on Github, but posting here for others. Data.Either has not implemented concat/traverse yet. Here's our either

``````const Right = x =>
({
chain: f => f(x),
ap: other => other.map(x),
traverse: (of, f) => f(x).map(Right),
map: f => Right(f(x)),
fold: (f, g) => g(x),
concat: o =>
o.fold(_ => Right(x),
y => Right(x.concat(y))),
inspect: () => `Right(\${x})`
})

const Left = x =>
({
chain: f => Left(x),
ap: other => Left(x),
traverse: (of, f) => of(Left(x)),
map: f => Left(x),
fold: (f, g) => f(x),
concat: o =>
o.fold(_ => Left(x),
y => o),
inspect: () => `Left(\${x})`
})

const fromNullable = x =>
x != null ? Right(x) : Left(null)

const tryCatch = f => {
try {
return Right(f())
} catch(e) {
return Left(e)
}
}

module.exports = { Right, Left, fromNullable, tryCatch, of: Right }`````` Sean Omlor
~ 4 years ago

Sweeet, thanks! FWIW I also added `isRight: true, isLeft: false` to `Right` and vice versa to `Left` in order to get `First` and `find` working. Really enjoying this course, thank you. Hank
~ 2 years ago

Hi, I am having some doubts on the `foldMap` example that returns `Left(null)` on the video, should it not be `Right(50)` since the `.concat` on `Right` is defined as: `concat: o => o.fold(_ => Right(x), y => Right(x.concat(y)))` ?

From what I understand, this is happening because the accumulator at that point will have `Right(50)` as a value, so when calling `.concat` with a `Left(null)` it will keep the value of `x` that it is currently holding.

Here is a working demo:

``````console.log(
Right(Sum(0))
.concat(Right(Sum(40)))
.concat(Right(Sum(10)))
.concat(Left(null))
.fold(e => `Left(\${e})`, s => `Sum(\${s.x})`)
);
`````` Hank
~ 2 years ago

Sorry, I double checked the video implementation and the definition of `Right.concat` in it returns a `Left(e)` when doing `Right(50).concat(Left(null))`. The one Brian posted is the one that only returns `Right`s for `Right.concat` on the `.concat`.

Is that a matter of choice or is there a standard? Jan Hesters
~ 2 years ago

There is no transcript, so here are all the examples:

``````const util = require("util");
import { List } from "immutable-ext";

const fromNullable = x => (x != null ? Right(x) : Left(null));

// Example 1
const Sum = x => ({
x,
concat: ({ x: y }) => Sum(x + y),
[util.inspect.custom]: () => `Sum(\${x})`
});

Sum.empty = () => Sum(0);

// Example 2
const Product = x => ({
x,
concat: ({ x: y }) => Product(x * y),
[util.inspect.custom]: () => `Product(\${x})`
});

Product.empty = () => Product(1);

// Example 3
const Any = x => ({
x,
concat: ({ x: y }) => Any(x || y),
[util.inspect.custom]: () => `Any(\${x})`
});

Any.empty = () => Any(false);

// Example 4
const All = x => ({
x,
concat: ({ x: y }) => All(x && y),
[util.inspect.custom]: () => `All(\${x})`
});

All.empty = () => All(true);

// Example 5
const Max = x => ({
x,
concat: ({ x: y }) => Max(x > y ? x : y),
[util.inspect.custom]: () => `Max(\${x})`
});

Max.empty = () => Max(-Infinity);

// Example 6
const Min = x => ({
x,
concat: ({ x: y }) => Min(x < y ? x : y),
[util.inspect.custom]: () => `Min(\${x})`
});

Min.empty = () => Min(Infinity);

// Example 7
const Right = x => ({
chain: f => f(x),
map: f => Right(f(x)),
fold: (f, g) => g(x),
concat: o => o.fold(e => Left(e), r => Right(x.concat(r))),
[util.inspect.custom]: () => `Right(\${x})`
});

const Left = x => ({
chain: f => Left(x),
map: f => Left(x),
fold: (f, g) => f(x),
concat: o => Left(x),
[util.inspect.custom]: () => `Left(\${x})`
});

const stats = List.of(
{ page: "Home", views: 40 },
{ page: "About", views: 10 },
{ page: "Blog", views: null }
);

stats.foldMap(x => fromNullable(x.views).map(Sum), Right(Sum(0)));
// Left(null)

// Example 8
const First = either => ({
fold: f => f(either),
concat: o => (either.isLeft ? o : First(either)),
[util.inspect.custom]: () => `Min(\${x})`
});

First.empty = () => First(Left());

const find = (xs, f) =>
List(xs)
.foldMap(x => First(f(x) ? Right(x) : Left()), First.empty())
.fold(x => x);

find([3, 4, 5, 6, 7], x => x > 4);
// Right(5)

// Example 9
const Fn = f => ({ fold: f, concat: o => Fn(x => f(x).concat(o.fold(x))) });

const hasVowels = x => !!x.match(/[aeiou]/gi);
const longWord = x => x.length >= 5;
const both = Fn(
compose(
All,
hasVowels
)
).concat(
Fn(
compose(
All,
longWord
)
)
);

[("gym", "bird", "lilac")].filter(x => both.fold(x).x);
// [lilac]

// Example 10
const Pair = (x, y) => ({
x,
y,
concat: ({ x: x1, y: y1 }) => Pair(x.concat(x1), y.concat(y1)),
[util.inspect.custom]: () => `Pair(\${x}, \${y})`
});``````