Last active
May 3, 2020 11:00
-
-
Save zaetrik/de43fe8d37313eb35deed1b076babdc3 to your computer and use it in GitHub Desktop.
Semigroup Type Class Introduction
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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