Skip to content

Instantly share code, notes, and snippets.

@jkachmar
Created April 7, 2017 21:20
Show Gist options
  • Select an option

  • Save jkachmar/60a06f9505f25e7fff7f72bf991d87c3 to your computer and use it in GitHub Desktop.

Select an option

Save jkachmar/60a06f9505f25e7fff7f72bf991d87c3 to your computer and use it in GitHub Desktop.
Contravariance in JS
const daggy = require('daggy');
/* ------------------------------------------------------------------------- */
// type Predicate a = a -> Bool
// a is the _input_ to the function
const Predicate = daggy.tagged('f');
// :: (a -> Bool) -> (b -> a) -> b -> Bool
// :: Predicate a ~> (b -> a) -> Predicate b
Predicate.prototype.contramap =
function (g) { // f :: b -> a
return Predicate(
// :: b -> (b -> a) -> (a -> Bool) -> Bool
// :: b -> Bool
x => this.f(g(x))
);
};
// isEven ~ Int -> Bool
// isEven :: Predicate Int
const isEven = Predicate(x => x % 2 === 0);
// lengthIsEven ~ String -> Bool
// lengthIsEven :: Predicate String
const lengthIsEven = isEven.contramap(x => x.length);
// console.log(lengthIsEven.f([1, 2]));
const ToString = daggy.tagged('f');
// :: (a -> String) -> (b -> a) -> (b -> String)
// :: ToString a ~> (b -> a) -> ToString b
ToString.prototype.contramap =
function (g) {
return ToString(
// :: b -> (b -> a) -> (a -> String) -> String
// :: b -> String
x => this.f(g(x))
);
};
// :: Int -> String
// :: ToString Int
const intToString =
ToString(x => `int(${x})`)
.contramap(x => x | 0);
// console.log(intToString.f(1));
// :: Array String -> String
// :: ToString (Array String)
const stringArrayToString =
ToString(x => `[ ${x} ]`)
.contramap(x => x.join(', '));
// console.log(stringArrayToString.f(['test', 'test', 'test']));
// :: ToString a -> Array a -> String
// :: ToString a -> ToString (Array a)
const arrayToString = t =>
stringArrayToString
.contramap(x => x.map(t.f));
// :: Array Int -> String
// :: ToString (Array Int)
const arrIntsToString =
arrayToString(intToString);
// console.log(arrIntsToString.f([1, 2, 3]));
// :: Array (Array Int) -> String
// :: ToString (Array (Array Int))
const matrixIntsToString =
arrayToString(arrIntsToString);
// console.log(matrixIntsToString.f([[1, 3, 5], [2, 4, 6]]));
/* ------------------------------------------------------------------------- */
// type Equivalence a => a -> a -> Bool
const Equivalence = daggy.tagged('f');
// :: (a -> a -> Bool) -> (b -> a) -> (b -> b -> Bool)
// :: Equivalence a ~> (b -> a) -> Equivalence b
Equivalence.prototype.contramap =
function (g) {
return Equivalence(
(x, y) => this.f(g(x), g(y))
);
};
// :: String -> String -> Bool
// :: Equivalence String
const searchCheck =
// Basic equivalence
Equivalence((x, y) => x === y)
// Remove symbols
.contramap(x => x.replace(/\W/, ''))
// Lowercase alphas
.contramap(x => x.toLowerCase());
// true
// console.log(searchCheck.f('Hello', "HELLO!"))
// false
// console.log(searchCheck.f('world', "werld"))
/* ------------------------------------------------------------------------- */
// :: Predicate Int
const greaterThanThree = Predicate(x => x > 3);
// :: Predicate Int
const lessThanSix = Predicate(x => x < 6);
// :: Predicate Int
const equalToTwo = Predicate(x => x === 2);
// :: Predicate a -> Array a -> Array a
const predFilter = pred => arr =>
arr.filter(pred.f);
// [ 2 ]
// console.log(predFilter(equalToTwo)([2, 3, 4, 5, 6]))
// [ 4, 5, 6 ]
// console.log(predFilter(greaterThanThree)([2, 3, 4, 5, 6]))
// [ 4, 5 ]
// console.log(predFilter(greaterThanThree)(predFilter(lessThanSix)([2, 3, 4, 5, 6])));
/* ------------------------------------------------------------------------- */
// Int -> Int -> Bool
// Equivalence Int
const equivEqual = Equivalence((x, y) => x === y);
// Int -> Int -> Bool
// Equivalence Int
const unequivEqual = Equivalence((x, y) => x !== y);
// :: (a -> a -> Bool) -> Array a -> Array (Array a))
// :: Equivalence a -> Array a -> Array (Array a))
const equiGroup = equiv => arr =>
[...new Set(arr)]
.map(groupBy =>
arr.filter(x =>
equiv.f(groupBy, x)));
// [[ 2, 2 ], [ 3, 3 ], [ 4, 4 ]]
// console.log(equiGroup(equivEqual)([2, 2, 3, 3, 4, 4]));
// [[ 2, 2 ], [ 3 ], [ 4, 4 ]]
// console.log(equiGroup(equivEqual)([2, 2, 3, 4, 4]));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment