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
// We can use the fold function to concatenate/merge an array of values | |
// with the concat method defined for the Monoid instance | |
// The fold function gets a little bit easier when using it with Monoids | |
// Let's take a look at the fp-ts implementation of fold for Monoids | |
export function fold<A>(M: Monoid<A>): (as: ReadonlyArray<A>) => A { | |
const foldM = foldSemigroup(M) | |
return (as) => foldM(M.empty, as) | |
} | |
// We see that the fold function for Monoids uses the fold function for Semigroups |
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
// Monoid type class | |
// Used to merge two contexts together | |
// Mostly taken from https://dev.to/gcanti/getting-started-with-fp-ts-monoid-ja0 | |
// A Monoid extends the Semigroup type class | |
// "A Monoid is any Semigroup that happens to have a special value which is "neutral" with respect to concat" - https://dev.to/gcanti/getting-started-with-fp-ts-monoid-ja0 | |
// empty does nothing else than returning that special neutral value | |
interface Monoid<A> extends Semigroup<A> { | |
readonly empty: A | |
} |
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
type Song = { | |
releaseYear: number; | |
title: string; | |
artistId: number; | |
}; | |
// We could also create a Semigroup instance for objects | |
const semigroupSong: Semigroup<Song> = { | |
concat: (song1: Song, song2: Song) => ({ | |
releaseYear: song1.releaseYear > song2.releaseYear ? song1.releaseYear : song2.releaseYear, // keep the most recent year |
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
// Merging two numbers or strings together is pretty easy | |
// but what if we would like to merge values that are wrapped inside a context like Option<A>? | |
// We need some special logic for that | |
// fp-ts exports a function that lets you create a Semigroup instance for an Option<A> | |
// What it does is check if both, x & y, are not `none` | |
// and if so it takes the the values from x & y and applies them to the concat method of the Semigroup instance we passed into getApplySemigroup | |
export function getApplySemigroup<A>(S: Semigroup<A>): Semigroup<Option<A>> { | |
return { | |
concat: (x, y) => (isSome(x) && isSome(y) ? some(S.concat(x.value, y.value)) : none) |
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's concat works only with two values | |
// If we would like to merge/concat more elements we have to use a function called fold | |
// If you understand JS's array.reduce you will understand fold | |
// The fold function for Semigroups from fp-ts is defined like this => | |
export function fold<A>(S: Semigroup<A>): (a: A, as: ReadonlyArray<A>) => A { | |
return (a, as) => as.reduce(S.concat, a) | |
} | |
// It takes in a Semigroup and returns a function that takes in an initial value A and an array of A (Array<A>) and returns an A | |
// So it folds/reduces an Array<A> into a single value A |
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 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
// Mostly taken from https://dev.to/gcanti/getting-started-with-fp-ts-ord-5f1e | |
// Now we could create min & max functions | |
function min<A>(O: Ord<A>): (x: A, y: A) => A { | |
return (x, y) => (O.compare(x, y) === 1 ? y : x); | |
} | |
function max<A>(O: Ord<A>): (x: A, y: A) => A { | |
return (x, y) => (O.compare(x, y) === 1 ? x : y); | |
} | |
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
// Ord type class | |
// => used for ordering things it contains types that admit a total ordering | |
// Mostly taken from https://dev.to/gcanti/getting-started-with-fp-ts-ord-5f1e | |
// -1 is for x < y | |
// 0 is for x === y | |
// 1 is for x > 1 | |
type Ordering = -1 | 0 | 1 | |
// Our interface for the Ord type class |
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
type Album = { | |
artist: Artist; | |
title: string; | |
albumId: number; | |
}; | |
const eqAlbumBySameArtist: Eq<Album> = contramap((album: Album) => album.artist)(eqArtist); | |
// Now we can check if an album is made by the same artist | |
eqAlbumBySameArtist.equals( |
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
// Eq type class | |
// => used to compare two inputs and check for equality | |
// Mostly taken from https://dev.to/gcanti/getting-started-with-fp-ts-setoid-39f3 | |
// Our interface for the Eq type class | |
// For something to be a member of the Eq type class it has to implement an equals method that returns true | |
interface Eq<A> { | |
// `true` if `x` equals `y` | |
readonly equals: (x: A, y: A) => boolean; | |
} |