Last active
May 3, 2020 09:25
-
-
Save zaetrik/7528477f0ee8cd8417b0bac376ffba5a to your computer and use it in GitHub Desktop.
Semigroup Type Class Objects
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 | |
title: song1.title.length > song2.title.length ? song1.title : song2.title, // keep the longer title | |
artistId: song2.artistId // keep the artistId from the second input | |
}) | |
} | |
// What we did here is defining a concat method for our Song type | |
// Basically we just defined functions or rules for every key in type Song for how the merging/concatenation of the value should happen | |
// We also could have used existing concat methods from other Semigroup instances like semigroupProduct if we wanted to multiply the two inputs | |
// This procedure is a lot of boilerplate | |
// We could reduce that and use a function from fp-ts | |
// fp-ts exports a function called getStructSemigroup | |
// getStructSemigroup allows us to create a Semigroup instance for objects | |
// Here we have to pass a Semigroup instance to every key in the object | |
// then the concat method of that Semigroup instance will be applied to the value of the key | |
import { getStructSemigroup, getJoinSemigroup, Semigroup, getLastSemigroup } from 'fp-ts/lib/Semigroup' | |
import { ordNumber } from "fp-ts/lib/Ord"; | |
const semigroupSong: Semigroup<Song> = getStructSemigroup({ | |
releaseYear: getJoinSemigroup(contramap((year: number) => year)(ordNumber)), // This creates a new Semigroup instance where we keep the larger number => most recent year | |
title: getJoinSemigroup(contramap((title: string) => title.length)(ordNumber)), // This creates a new Semigroup instance where we keep the longer string | |
artistId: getLastSemigroup<number>(), // Semigroup that returns the last/second element passed to concat | |
}); | |
// We can now merge/concatenate two Users | |
semigroupSong.concat( | |
{ | |
releaseYear: 2020, | |
title: "hello", | |
artistId: 1 | |
}, | |
{ | |
releaseYear: 2018, | |
title: "hello my friend", | |
artistId: 1 | |
} | |
) // { releaseYear: 2020, title: "hello my friend", artistId: 1 } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment