Skip to content

Instantly share code, notes, and snippets.

@ddanielbee
Last active June 7, 2018 14:45
Show Gist options
  • Save ddanielbee/9eb478e93c213db7cabee85c18918747 to your computer and use it in GitHub Desktop.
Save ddanielbee/9eb478e93c213db7cabee85c18918747 to your computer and use it in GitHub Desktop.
// Utils
const fantasyConcat = (semiOne, semiTwo) => {
if (
semiOne.instances &&
semiTwo.instances &&
semiOne.instances.includes("Semigroup") &&
semiTwo.instances.includes("Semigroup")
)
return semiOne.concat(semiTwo);
if (Array.isArray(semiOne) && Array.isArray(semiTwo)) return semiOne.concat(semiTwo);
if (typeof semiOne === "string" && typeof semiTwo === "string") return `${semiOne}${semiTwo}`;
if (typeof semiOne === "object" && typeof semiTwo === "object")
return Object.assign({}, semiOne, semiTwo);
throw new Error("Not instances of semigroup, or concatenable primitives!");
};
const compose = (...fns) => x => fns.reduceRight((acc, cur) => cur(acc), x);
const fantasyMap = (fn, value) => {
if (typeof value.instances !== "undefined" && value.instances.includes("Functor"))
return value.map(fn);
return fn(value);
};
const id = x => x;
const equalArrays = (xs, ys) => {
if (xs.length !== ys.length) return false;
return xs
.sort((a, b) => a < b)
.map((x, i) => fantasyEquals(x, ys.sort((a, b) => a < b)[i]))
.every(bool => bool);
};
const equalObjects = (x, y) => {
if (Object.keys(x).length !== Object.keys(y).length) return false;
return Object.keys(x)
.map(key => y.hasOwnProperty(key) && fantasyEquals(x[key], y[key]))
.every(bool => bool === true);
};
const sameType = (x, y) =>
typeof x === typeof y &&
typeof x.constructor !== "undefined" &&
typeof y.constructor !== "undefined" &&
x.constructor.typeRepresentation === y.constructor.typeRepresentation;
const fantasyEquals = (x, y) => {
if (!sameType(x, y)) return false;
if (
typeof x.constructor.typeRepresentation !== "undefined" &&
typeof y.constructor.typeRepresentation !== "undefined" &&
x.constructor.typeRepresentation === y.constructor.typeRepresentation
)
return fantasyEquals(x.value(), y.value());
if (Array.isArray(x)) return equalArrays(x, y);
if (typeof x === "object") return equalObjects(x, y);
return x === y;
};
// Maybe implementation with Instances of
// Setoid ✅
// Semigroup ✅
// Monoid ✅
// Functor ✅
// Apply ✅
// Applicative ✅
// Foldable ✅
// Traversable ✅?¿?
// Chain ✅
// Monad ✅
// Success!
const Nothing = value => ({
value: () => "Nothing",
isNothing: () => true,
isJust: () => false,
equals: other => other.isNothing(),
concat: other => other,
map: fn => Nothing(),
ap: other => Nothing(),
reduce: (fn, initial) => initial,
traverse: (typeRepresentative, fn) => typeRepresentative.of(Nothing()),
chain: fn => Nothing(),
constructor: Maybe,
toString: () => "Nothing",
inspect: () => "Nothing",
instances: ["Semigroup", "Monoid", "Functor", "Apply", "Applicative", "Foldable", "Traversable", "Chain", "Monad"]
});
const Just = value => ({
value: () => value,
isNothing: () => false,
isJust: () => true,
equals: other => (other.isNothing() ? false : fantasyEquals(Just(value), other)),
concat: other => (other.isNothing() ? Just(value) : Just(fantasyConcat(value, other.value()))),
map: fn => Just(fantasyMap(fn, value)),
ap: other => (other.isJust() ? Just(fantasyMap(other.value(), value)) : other),
reduce: (fn, initial) => fn(initial, value),
traverse: (typeRepresentative, fn) => fantasyMap(Just, fn(value)),
chain: fn => fn(value),
constructor: Maybe,
toString: () => `Just(${value})`,
inspect: () => `Just(${value})`,
instances: ["Semigroup", "Monoid", "Functor", "Apply", "Applicative", "Foldable", "Traversable", "Chain", "Monad"]
});
const Maybe = {
empty: () => Nothing(),
of: value => Just(value),
typeRepresentation: "Maybe"
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment