Last active
March 4, 2021 20:03
-
-
Save lupuszr/4ca80d206f5c6b67c95d53060831d993 to your computer and use it in GitHub Desktop.
Playing with Contravariant functors in typescript - Contravariant functor for comparison
This file contains 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
Lets define a sum type `Ordering` with its data constructors: | |
```typescript | |
class LT {} | |
class EQ {} | |
class GT {} | |
type Ordering = LT | EQ | GT; | |
class Comparison<A> { | |
constructor(public runComparison: ((a: A) => (b: A) => Ordering)){} | |
} | |
``` | |
// Because of the position of the parameter we can see that this is a contravariant structure | |
Example usage: | |
- We can compare numbers | |
``` | |
const x = new Comparison<number>((a) => b => { | |
if (a === b) return new EQ(); | |
if (a > b) return new GT(); | |
if (a < b) return new LT(); | |
}) | |
``` | |
Now lets define our contravariant functor over Comparison. | |
As you know functors map has a type of: <A, B>(f: (a: A) => B) => (a: F A) => F B. | |
And while functors pack things (think of array, or function composition) the contravariant functors "unpack". | |
Its type is: <A, B>(f: (b: B) => A) => (a: F A) => F B | |
For `Comparison` this is: | |
```typescript | |
type contramapT = <A, B>(f: (b: B) => A) => (a: Comparison<A>) => Comparison<B>; | |
const contramap: contramapT = (f) => compC => { | |
return new Comparison(a => b => compC.runComparison(f(a))(f(b))) | |
} | |
``` | |
Let say we have some users which age we would like to compare. | |
```typescript | |
const compareNumbers = new Comparison<number>((a) => b => { | |
if (a === b) return new EQ(); | |
if (a > b) return new GT(); | |
if (a < b) return new LT(); | |
}); | |
type userT = { | |
name: string; | |
age: number; | |
} | |
const user1 = { name: "Igor", age: 25 } | |
const user2 = { name: "Ivan", age: 28 } | |
const userAgeComparer = contramap<number, userT>(a => { | |
return a.age; | |
})(compareNumbers) | |
const result = userAgeComparer.runComparison(user1)(user2); | |
``` | |
As you can see from this trivial example we generated a new comparer for our user. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment