Skip to content

Commit

Permalink
fix!: Tidy up about Ord and Eq (#34)
Browse files Browse the repository at this point in the history
  • Loading branch information
MikuroXina authored Dec 25, 2022
1 parent 8c7df65 commit 4e5c496
Show file tree
Hide file tree
Showing 21 changed files with 626 additions and 458 deletions.
4 changes: 4 additions & 0 deletions src/bool.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { Monoid } from "./type-class/monoid.js";
import { fromEquality } from "./type-class/eq.js";

export const andMonoid: Monoid<boolean> = {
identity: true,
Expand All @@ -8,3 +9,6 @@ export const orMonoid: Monoid<boolean> = {
identity: false,
combine: (l, r) => l || r,
};

export const equality = (lhs: boolean, rhs: boolean): boolean => lhs === rhs;
export const eq = fromEquality(() => equality)();
29 changes: 10 additions & 19 deletions src/cat.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
/* eslint-disable no-console */

import { Eq, PartialEq, eqSymbol } from "./type-class/eq.js";
import type { Ord, PartialOrd } from "./type-class/ord.js";

import type { Monad1 } from "./type-class/monad.js";
import { fromProjection as eqFromProjection } from "./type-class/eq.js";
import { fromProjection as ordFromProjection } from "./type-class/ord.js";
import { fromProjection as partialEqFromProjection } from "./type-class/partial-eq.js";
import { fromProjection as partialOrdFromProjection } from "./type-class/partial-ord.js";

declare const catNominal: unique symbol;
export type CatHktKey = typeof catNominal;
Expand All @@ -17,22 +18,12 @@ export const cat = <T>(value: T): Cat<T> => ({
feed: <U>(fn: (t: T) => U) => cat(fn(value)),
});

export const partialEq = <T>(equality: PartialEq<T>): PartialEq<Cat<T>> => ({
eq: (l, r) => equality.eq(l.value, r.value),
});
export const eq = <T>(equality: Eq<T>): Eq<Cat<T>> => ({
...partialEq(equality),
[eqSymbol]: true,
});
export const partialOrd = <T>(order: PartialOrd<T>): PartialOrd<Cat<T>> => ({
...partialEq(order),
partialCmp: (l, r) => order.partialCmp(l.value, r.value),
});
export const ord = <T>(order: Ord<T>): Ord<Cat<T>> => ({
...partialOrd(order),
cmp: (l, r) => order.cmp(l.value, r.value),
[eqSymbol]: true,
});
export const get = <T>({ value }: Cat<T>): T => value;

export const partialEq = partialEqFromProjection<CatHktKey>(get);
export const eq = eqFromProjection<CatHktKey>(get);
export const partialOrd = partialOrdFromProjection<CatHktKey>(get);
export const ord = ordFromProjection<CatHktKey>(get);

export const inspect =
<T>(inspector: (t: T) => void) =>
Expand Down
95 changes: 54 additions & 41 deletions src/cofree.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Eq, PartialEq, eqSymbol } from "./type-class/eq.js";
import { Eq, fromEquality } from "./type-class/eq.js";
import {
Lazy,
force,
Expand All @@ -9,7 +9,9 @@ import {
partialEq as lazyPartialEq,
partialOrd as lazyPartialOrd,
} from "./lazy.js";
import type { Ord, PartialOrd } from "./type-class/ord.js";
import { Ord, fromCmp } from "./type-class/ord.js";
import { PartialEq, fromPartialEquality } from "./type-class/partial-eq.js";
import { PartialOrd, fromPartialCmp } from "./type-class/partial-ord.js";
import {
Tuple,
eq as tupleEq,
Expand All @@ -21,61 +23,72 @@ import {

import type { Functor1 } from "./type-class/functor.js";
import type { GetHktA1 } from "./hkt.js";
import type { Option } from "./option.js";
import type { Ordering } from "./ordering.js";
import { compose } from "./func.js";

declare const cofreeNominal: unique symbol;
export type CofreeHktKey = typeof cofreeNominal;
export type Cofree<F, A> = Lazy<Tuple<A, GetHktA1<F, Cofree<F, A>>>>;

export const partialEq = <F, A>(
equalityA: PartialEq<A>,
equalityFA: <T>(equality: PartialEq<T>) => PartialEq<GetHktA1<F, T>>,
): PartialEq<Cofree<F, A>> => {
const self: PartialEq<Cofree<F, A>> = lazyPartialEq(
tuplePartialEq(equalityA, {
eq: (l, r) => equalityFA(self).eq(l, r),
}),
);
export const partialEquality = <F, A>({
equalityA,
equalityFA,
}: {
equalityA: PartialEq<A>;
equalityFA: <T>(equality: PartialEq<T>) => PartialEq<GetHktA1<F, T>>;
}): ((l: Cofree<F, A>, r: Cofree<F, A>) => boolean) => {
const self: (l: Cofree<F, A>, r: Cofree<F, A>) => boolean = lazyPartialEq<
Tuple<A, GetHktA1<F, Cofree<F, A>>>
>(tuplePartialEq({ equalityA, equalityB: equalityFA(fromPartialEquality(() => self)()) })).eq;
return self;
};
export const eq = <F, A>(
equalityA: Eq<A>,
equalityFA: <T>(equality: Eq<T>) => Eq<GetHktA1<F, T>>,
): Eq<Cofree<F, A>> => {
const self: Eq<Cofree<F, A>> = lazyEq(
tupleEq(equalityA, {
eq: (l, r) => equalityFA(self).eq(l, r),
[eqSymbol]: true,
}),
);
export const partialEq = fromPartialEquality(partialEquality);
export const equality = <F, A>({
equalityA,
equalityFA,
}: {
equalityA: Eq<A>;
equalityFA: <T>(equality: Eq<T>) => Eq<GetHktA1<F, T>>;
}): ((l: Cofree<F, A>, r: Cofree<F, A>) => boolean) => {
const self: (l: Cofree<F, A>, r: Cofree<F, A>) => boolean = lazyEq<
Tuple<A, GetHktA1<F, Cofree<F, A>>>
>(tupleEq({ equalityA, equalityB: equalityFA(fromEquality(() => self)()) })).eq;
return self;
};
export const partialOrd = <F, A>(
orderA: PartialOrd<A>,
orderFA: <T>(order: PartialOrd<T>) => PartialOrd<GetHktA1<F, T>>,
): PartialOrd<Cofree<F, A>> => {
const self: PartialOrd<Cofree<F, A>> = lazyPartialOrd(
tuplePartialOrd(orderA, {
eq: (l, r) => orderFA(self).eq(l, r),
partialCmp: (l, r) => orderFA(self).partialCmp(l, r),
export const eq = fromEquality(equality);
export const partialCmp = <F, A>({
orderA,
orderFA,
}: {
orderA: PartialOrd<A>;
orderFA: <T>(order: PartialOrd<T>) => PartialOrd<GetHktA1<F, T>>;
}): ((l: Cofree<F, A>, r: Cofree<F, A>) => Option<Ordering>) => {
const self: (l: Cofree<F, A>, r: Cofree<F, A>) => Option<Ordering> = lazyPartialOrd(
tuplePartialOrd({
ordA: orderA,
ordB: orderFA(fromPartialCmp(() => self)()),
}),
);
).partialCmp;
return self;
};
export const ord = <F, A>(
orderA: Ord<A>,
orderFA: <T>(order: Ord<T>) => Ord<GetHktA1<F, T>>,
): Ord<Cofree<F, A>> => {
const self: Ord<Cofree<F, A>> = lazyOrd(
tupleOrd(orderA, {
eq: (l, r) => orderFA(self).eq(l, r),
[eqSymbol]: true,
partialCmp: (l, r) => orderFA(self).partialCmp(l, r),
cmp: (l, r) => orderFA(self).cmp(l, r),
export const partialOrd = fromPartialCmp(partialCmp);
export const cmp = <F, A>({
orderA,
orderFA,
}: {
orderA: Ord<A>;
orderFA: <T>(order: Ord<T>) => Ord<GetHktA1<F, T>>;
}): ((l: Cofree<F, A>, r: Cofree<F, A>) => Ordering) => {
const self: (l: Cofree<F, A>, r: Cofree<F, A>) => Ordering = lazyOrd(
tupleOrd({
ordA: orderA,
ordB: orderFA(fromCmp(() => self)()),
}),
);
).cmp;
return self;
};
export const ord = fromCmp(cmp);

export const defer: <F, A>(fn: () => [A, GetHktA1<F, Cofree<F, A>>]) => Cofree<F, A> = lazyDefer;

Expand Down
169 changes: 73 additions & 96 deletions src/free.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import * as Option from "./option.js";
import * as Result from "./result.js";

import { Eq, PartialEq, eqSymbol } from "./type-class/eq.js";
import { Eq, fromEquality } from "./type-class/eq.js";
import { Monad1, Monad2Monoid, kleisli } from "./type-class/monad.js";
import type { Ord, PartialOrd } from "./type-class/ord.js";
import { greater, less } from "./ordering.js";
import { Ord, fromCmp } from "./type-class/ord.js";
import { Ordering, greater, less } from "./ordering.js";
import { PartialEq, fromPartialEquality } from "./type-class/partial-eq.js";
import { PartialOrd, fromPartialCmp } from "./type-class/partial-ord.js";

import type { Applicative1 } from "./type-class/applicative.js";
import type { Functor1 } from "./type-class/functor.js";
Expand All @@ -26,115 +28,90 @@ export const isNode = <F, A>(free: Free<F, A>): free is Node<F, A> => free[0] ==

export type Free<F, A> = Pure<A> | Node<F, A>;

export const partialEq = <F, A>(
equalityA: PartialEq<A>,
equalityFA: <T>(equality: PartialEq<T>) => PartialEq<GetHktA1<F, T>>,
): PartialEq<Free<F, A>> => {
const self: PartialEq<Free<F, A>> = {
eq: (l, r) => {
if (isPure(l) && isPure(r)) {
return equalityA.eq(l[1], r[1]);
}
if (isNode(l) && isNode(r)) {
return equalityFA(self).eq(l[1], r[1]);
}
return false;
},
export const partialEquality = <F, A>({
equalityA,
equalityFA,
}: {
equalityA: PartialEq<A>;
equalityFA: <T>(equality: PartialEq<T>) => PartialEq<GetHktA1<F, T>>;
}) => {
const self = (l: Free<F, A>, r: Free<F, A>): boolean => {
if (isPure(l) && isPure(r)) {
return equalityA.eq(l[1], r[1]);
}
if (isNode(l) && isNode(r)) {
return equalityFA(fromPartialEquality(() => self)()).eq(l[1], r[1]);
}
return false;
};
return self;
};
export const eq = <F, A>(
equalityA: Eq<A>,
equalityFA: <T>(equality: Eq<T>) => Eq<GetHktA1<F, T>>,
): Eq<Free<F, A>> => {
const self: Eq<Free<F, A>> = {
eq: (l, r) => {
if (isPure(l) && isPure(r)) {
return equalityA.eq(l[1], r[1]);
}
if (isNode(l) && isNode(r)) {
return equalityFA(self).eq(l[1], r[1]);
}
return false;
},
[eqSymbol]: true,
export const partialEq = fromPartialEquality(partialEquality);
export const equality = <F, A>({
equalityA,
equalityFA,
}: {
equalityA: Eq<A>;
equalityFA: <T>(equality: Eq<T>) => Eq<GetHktA1<F, T>>;
}) => {
const self = (l: Free<F, A>, r: Free<F, A>): boolean => {
if (isPure(l) && isPure(r)) {
return equalityA.eq(l[1], r[1]);
}
if (isNode(l) && isNode(r)) {
return equalityFA(fromEquality(() => self)()).eq(l[1], r[1]);
}
return false;
};
return self;
};
export const partialOrd = <F, A>(
orderA: PartialOrd<A>,
orderFA: <T>(order: PartialOrd<T>) => PartialOrd<GetHktA1<F, T>>,
): PartialOrd<Free<F, A>> => {
const self: PartialOrd<Free<F, A>> = {
eq: (l, r) => {
if (isPure(l) && isPure(r)) {
return orderA.eq(l[1], r[1]);
}
if (isNode(l) && isNode(r)) {
return orderFA(self).eq(l[1], r[1]);
}
return false;
},
partialCmp: (l, r) => {
// considered that Pure is lesser than Node
if (isPure(l)) {
if (isPure(r)) {
return orderA.partialCmp(l[1], r[1]);
}
return Option.some(less);
}
export const eq = fromEquality(equality);
export const partialCmp = <F, A>({
orderA,
orderFA,
}: {
orderA: PartialOrd<A>;
orderFA: <T>(order: PartialOrd<T>) => PartialOrd<GetHktA1<F, T>>;
}) => {
const self = (l: Free<F, A>, r: Free<F, A>): Option.Option<Ordering> => {
// considered that Pure is lesser than Node
if (isPure(l)) {
if (isPure(r)) {
return Option.some(greater);
return orderA.partialCmp(l[1], r[1]);
}
return orderFA(self).partialCmp(l[1], r[1]);
},
return Option.some(less);
}
if (isPure(r)) {
return Option.some(greater);
}
return orderFA(fromPartialCmp(() => self)()).partialCmp(l[1], r[1]);
};
return self;
};
export const ord = <F, A>(
orderA: Ord<A>,
orderFA: <T>(order: Ord<T>) => Ord<GetHktA1<F, T>>,
): Ord<Free<F, A>> => {
const self: Ord<Free<F, A>> = {
eq: (l, r) => {
if (isPure(l) && isPure(r)) {
return orderA.eq(l[1], r[1]);
}
if (isNode(l) && isNode(r)) {
return orderFA(self).eq(l[1], r[1]);
}
return false;
},
[eqSymbol]: true,
partialCmp: (l, r) => {
// considered that Pure is lesser than Node
if (isPure(l)) {
if (isPure(r)) {
return orderA.partialCmp(l[1], r[1]);
}
return Option.some(less);
}
export const partialOrd = fromPartialCmp(partialCmp);
export const cmp = <F, A>({
orderA,
orderFA,
}: {
orderA: Ord<A>;
orderFA: <T>(order: Ord<T>) => Ord<GetHktA1<F, T>>;
}) => {
const self = (l: Free<F, A>, r: Free<F, A>): Ordering => {
// considered that Pure is lesser than Node
if (isPure(l)) {
if (isPure(r)) {
return Option.some(greater);
return orderA.cmp(l[1], r[1]);
}
return orderFA(self).partialCmp(l[1], r[1]);
},
cmp: (l, r) => {
// considered that Pure is lesser than Node
if (isPure(l)) {
if (isPure(r)) {
return orderA.cmp(l[1], r[1]);
}
return less;
}
if (isPure(r)) {
return greater;
}
return orderFA(self).cmp(l[1], r[1]);
},
return less;
}
if (isPure(r)) {
return greater;
}
return orderFA(fromCmp(() => self)()).cmp(l[1], r[1]);
};
return self;
};
export const ord = fromCmp(cmp);

export const retract =
<F>(monad: Monad1<F>) =>
Expand Down
Loading

0 comments on commit 4e5c496

Please sign in to comment.