Skip to content

Instantly share code, notes, and snippets.

@lupuszr
Last active March 4, 2021 20:03
Show Gist options
  • Save lupuszr/4ca80d206f5c6b67c95d53060831d993 to your computer and use it in GitHub Desktop.
Save lupuszr/4ca80d206f5c6b67c95d53060831d993 to your computer and use it in GitHub Desktop.
Playing with Contravariant functors in typescript - Contravariant functor for comparison
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