A gallery of monoid definitions and some use cases
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
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 }
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.
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})`)
);
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?
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})`
});