Skip to content

Instantly share code, notes, and snippets.

@zaetrik
Last active May 3, 2020 09:25
Show Gist options
  • Save zaetrik/7528477f0ee8cd8417b0bac376ffba5a to your computer and use it in GitHub Desktop.
Save zaetrik/7528477f0ee8cd8417b0bac376ffba5a to your computer and use it in GitHub Desktop.
Semigroup Type Class Objects
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