Skip to content

Instantly share code, notes, and snippets.

@zaetrik
Last active May 3, 2020 11:00
Show Gist options
  • Save zaetrik/de43fe8d37313eb35deed1b076babdc3 to your computer and use it in GitHub Desktop.
Save zaetrik/de43fe8d37313eb35deed1b076babdc3 to your computer and use it in GitHub Desktop.
Semigroup Type Class Introduction
// Semigroup type class
// Used to merge two contexts together
// Mostly taken from https://dev.to/gcanti/getting-started-with-fp-ts-semigroup-2mf7
// Our interface for the Semigroup type class
// For something to be a member of the Semigroup type class it has to implement a concat method
// that "merges" two As together and returns a new A
// concat has to be associative, which means => (x * y) * z = x * (y * z)
interface Semigroup<A> {
concat: (x: A, y: A) => A
}
// This is how we could implement a Semigroup (number, *) for multiplication
// number `Semigroup` under multiplication
const semigroupProduct: Semigroup<number> = {
concat: (x, y) => x * y
}
// Or a Semigroup (string, +) for concatenating two strings
const semigroupString: Semigroup<string> = {
concat: (x, y) => x + y
}
// concatenating strings or multiplying numbers are both associative operations
// If we would like to implement a Semigroup for a type that has no associative operation we could do the following =>
// We can create two Semigroups =>
// Always return the first argument
function getFirstSemigroup<A = never>(): Semigroup<A> {
return { concat: (x, y) => x }
}
// Always return the second argument
function getLastSemigroup<A = never>(): Semigroup<A> {
return { concat: (x, y) => y }
}
// With that logic (returning the first or last element)
// we could also derive two different Semigroups from a type that already has a Ord instance defined =>
// Always return the minimum of two values
function getMinSemigroup<A>(O: Ord<A>): Semigroup<A> {
return {
concat: (x, y) => (O.compare(x, y) === 1 ? y : x) // this is the min function we defined for the Ord type class
}
}
// Always return the maximum of two values
function getMaxSemigroup<A>(O: Ord<A>): Semigroup<A> {
return {
concat: (x, y) => (O.compare(x, y) === 1 ? x : y) // this is the max function we defined for the Ord type class
}
}
// Another way of solving the issue with the missing associative operation is this =>
// We just create a Semigroup instance for the type Array<A> => called `free semigroup` of A
function getArraySemigroup<A = never>(): Semigroup<Array<A>> {
return { concat: (x, y) => x.concat(y) } // x.concat is the native concat method for arrays
}
// and put the type A into a singleton list => [A]
function of<A>(a: A): Array<A> {
return [a]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment