Skip to content

Commit

Permalink
feat: Add PartialEqUnary implementations (#247)
Browse files Browse the repository at this point in the history
  • Loading branch information
MikuroXina authored Jul 24, 2024
1 parent ea84157 commit c6f2252
Show file tree
Hide file tree
Showing 18 changed files with 251 additions and 76 deletions.
20 changes: 12 additions & 8 deletions src/array.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,16 @@ import type { Reduce } from "./type-class/reduce.ts";
import type { Traversable } from "./type-class/traversable.ts";

export const partialEquality =
<T>(equality: PartialEq<T>) =>
(l: readonly T[], r: readonly T[]): boolean =>
<L, R = L>(equality: PartialEq<L, R>) =>
(l: readonly L[], r: readonly R[]): boolean =>
l.length === r.length &&
l.every((left, i) => equality.eq(left, r[i]));
export const partialEq: <T>(equality: PartialEq<T>) => PartialEq<T[]> =
fromPartialEquality(partialEquality);
export const partialEq: <L, R>(
equality: PartialEq<L, R>,
) => PartialEq<L[], R[]> = fromPartialEquality(partialEquality);
export const partialCmp =
<T>(order: PartialOrd<T>) =>
(l: readonly T[], r: readonly T[]): Option<Ordering> =>
<L, R = L>(order: PartialOrd<L, R>) =>
(l: readonly L[], r: readonly R[]): Option<Ordering> =>
foldR((
next: Option<Ordering>,
): (acc: Option<Ordering>) => Option<Ordering> =>
Expand All @@ -44,10 +45,13 @@ export const partialCmp =
export const partialOrd: <T>(order: PartialOrd<T>) => PartialOrd<T[]> =
fromPartialCmp(partialCmp);
export const equality =
<T>(equality: Eq<T>) => (l: readonly T[], r: readonly T[]): boolean =>
<L, R = L>(equality: Eq<L, R>) =>
(l: readonly L[], r: readonly R[]): boolean =>
l.length === r.length &&
l.every((left, i) => equality.eq(left, r[i]));
export const eq: <T>(equality: Eq<T>) => Eq<T[]> = fromEquality(equality);
export const eq: <L, R = L>(equality: Eq<L, R>) => Eq<L[], R[]> = fromEquality(
equality,
);
export const cmp =
<T>(order: Ord<T>) => (l: readonly T[], r: readonly T[]): Ordering =>
foldR(and)(Math.sign(l.length - r.length) as Ordering)(
Expand Down
18 changes: 18 additions & 0 deletions src/cofree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { fromCmp, type Ord } from "./type-class/ord.ts";
import {
fromPartialEquality,
type PartialEq,
type PartialEqUnary,
} from "./type-class/partial-eq.ts";
import { fromPartialCmp, type PartialOrd } from "./type-class/partial-ord.ts";
import {
Expand Down Expand Up @@ -143,6 +144,23 @@ export const ord: <F, A>({
orderFA: <T>(order: Ord<T>) => Ord<Get1<F, T>>;
}) => Ord<Cofree<F, A>> = fromCmp(cmp);

export const partialEqUnary = <F>(
eqUnary: PartialEqUnary<F>,
): PartialEqUnary<CofreeHkt> => ({
liftEq: <Lhs, Rhs>(
equality: (l: Lhs, r: Rhs) => boolean,
): (l: Cofree<F, Lhs>, r: Cofree<F, Rhs>) => boolean => {
const self = (l: Cofree<F, Lhs>, r: Cofree<F, Rhs>): boolean =>
lazyPartialEq({
eq: equality,
}).eq(l.current, r.current) &&
lazyPartialEq({
eq: eqUnary.liftEq(self),
}).eq(l.rest, r.rest);
return self;
},
});

/**
* Creates a new `Cofree` from the inner function.
*
Expand Down
8 changes: 8 additions & 0 deletions src/compose.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { type Applicative, liftA2 } from "./type-class/applicative.ts";
import { collect, type Distributive } from "./type-class/distributive.ts";
import type { Foldable } from "./type-class/foldable.ts";
import type { Functor } from "./type-class/functor.ts";
import type { PartialEqUnary } from "./type-class/partial-eq.ts";
import type { Traversable } from "./type-class/traversable.ts";

/**
Expand All @@ -21,6 +22,13 @@ export interface ComposeHkt extends Hkt3 {
readonly type: Compose<this["arg3"], this["arg2"], this["arg1"]>;
}

export const partialEqUnary = <F, G>(
eqUnaryF: PartialEqUnary<F>,
eqUnaryG: PartialEqUnary<G>,
): PartialEqUnary<Apply2Only<Apply3Only<ComposeHkt, F>, G>> => ({
liftEq: (equality) => eqUnaryF.liftEq(eqUnaryG.liftEq(equality)),
});

export const newCompose = <F, G, T>(
fgt: Get1<F, Get1<G, T>>,
): Compose<F, G, T> => fgt;
Expand Down
9 changes: 8 additions & 1 deletion src/const.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import type { Foldable } from "./type-class/foldable.ts";
import type { Functor } from "./type-class/functor.ts";
import type { Monoid } from "./type-class/monoid.ts";
import type { Ord } from "./type-class/ord.ts";
import type { PartialEq } from "./type-class/partial-eq.ts";
import type { PartialEq, PartialEqUnary } from "./type-class/partial-eq.ts";
import type { PartialOrd } from "./type-class/partial-ord.ts";
import type { SemiGroupoid } from "./type-class/semi-groupoid.ts";

Expand Down Expand Up @@ -40,6 +40,13 @@ export const ord = <A, B>(order: Ord<A>): Ord<Const<A, B>> => ({
[eqSymbol]: true,
});

export const partialEqUnary = <A>(
equality: PartialEq<A>,
): PartialEqUnary<Apply2Only<ConstHkt, A>> => ({
liftEq: <L, R>() => (l: Const<A, L>, r: Const<A, R>): boolean =>
equality.eq(l.getConst, r.getConst),
});

export const compose =
<B, C>(_left: Const<B, C>) => <A>(right: Const<A, B>): Const<A, C> => right;

Expand Down
33 changes: 33 additions & 0 deletions src/control-flow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ import {
mapDecoder,
} from "./serial.ts";
import type { Bifunctor } from "./type-class/bifunctor.ts";
import type { PartialEq, PartialEqUnary } from "./type-class/partial-eq.ts";
import { type Eq, eqSymbol } from "./type-class/eq.ts";

const continueSymbol = Symbol("ControlFlowContinue");
/**
Expand All @@ -43,6 +45,37 @@ export const newBreak = <B>(b: B): Break<B> => [breakSymbol, b];
*/
export type ControlFlow<B, C = never[]> = Continue<C> | Break<B>;

export const partialEq = <B, C>(
equalityB: PartialEq<B>,
equalityC: PartialEq<C>,
): PartialEq<ControlFlow<B, C>> => ({
eq: (l, r) =>
isBreak(l) && isBreak(r)
? equalityB.eq(l[1], r[1])
: isContinue(l) && isContinue(r) && equalityC.eq(l[1], r[1]),
});
export const eq = <B, C>(
equalityB: Eq<B>,
equalityC: Eq<C>,
): Eq<ControlFlow<B, C>> => ({
eq: (l, r) =>
isBreak(l) && isBreak(r)
? equalityB.eq(l[1], r[1])
: isContinue(l) && isContinue(r) && equalityC.eq(l[1], r[1]),
[eqSymbol]: true,
});

export const partialEqUnary = <B>(
equalityB: PartialEq<B>,
): PartialEqUnary<Apply2Only<ControlFlowHkt, B>> => ({
liftEq:
<L, R>(equality: (l: L, r: R) => boolean) =>
(l: ControlFlow<B, L>, r: ControlFlow<B, R>): boolean =>
isBreak(l) && isBreak(r)
? equalityB.eq(l[1], r[1])
: isContinue(l) && isContinue(r) && equality(l[1], r[1]),
});

export const isContinue = <B, C>(cf: ControlFlow<B, C>): cf is Continue<C> =>
cf[0] === continueSymbol;
export const isBreak = <B, C>(cf: ControlFlow<B, C>): cf is Break<B> =>
Expand Down
16 changes: 16 additions & 0 deletions src/free.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import { fromCmp, type Ord } from "./type-class/ord.ts";
import {
fromPartialEquality,
type PartialEq,
type PartialEqUnary,
} from "./type-class/partial-eq.ts";
import { fromPartialCmp, type PartialOrd } from "./type-class/partial-ord.ts";
import type { Pure } from "./type-class/pure.ts";
Expand Down Expand Up @@ -74,6 +75,21 @@ export const isBind = <F, T>(fr: Free<F, T>): fr is Bind<F, T> =>
*/
export type Free<F, T> = Return<T> | Bind<F, T>;

export const partialEqUnary = <F>(
eqUnary: PartialEqUnary<F>,
): PartialEqUnary<Apply2Only<FreeHkt, F>> => ({
liftEq: <L, R = L>(
equality: (l: L, r: R) => boolean,
): (l: Free<F, L>, r: Free<F, R>) => boolean => {
const self = (l: Free<F, L>, r: Free<F, R>): boolean =>
isReturn(l) && isReturn(r)
? equality(l[1], r[1])
: isBind(l) && isBind(r) &&
Coyoneda.partialEqUnary(eqUnary).liftEq(self)(l[1], r[1]);
return self;
},
});

/**
* Wraps a `Free` item on `F` into a new `Free`.
*/
Expand Down
6 changes: 6 additions & 0 deletions src/identity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import type { Comonad } from "./type-class/comonad.ts";
import type { Distributive } from "./type-class/distributive.ts";
import type { Functor } from "./type-class/functor.ts";
import type { Monad } from "./type-class/monad.ts";
import type { PartialEqUnary } from "./type-class/partial-eq.ts";
import type { Settable } from "./type-class/settable.ts";
import type { Traversable } from "./type-class/traversable.ts";

Expand Down Expand Up @@ -85,3 +86,8 @@ export const settable: Settable<IdentityHkt> = {
...distributive,
untainted: id,
};

/**
* The `PartialEqUnary` instance for `Identity`.
*/
export const partialEqUnary: PartialEqUnary<IdentityHkt> = { liftEq: id };
17 changes: 12 additions & 5 deletions src/lazy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
import {
fromProjection as partialEqFromProjection,
type PartialEq,
type PartialEqUnary,
} from "./type-class/partial-eq.ts";
import {
fromProjection as partialOrdFromProjection,
Expand Down Expand Up @@ -96,17 +97,23 @@ export const force = <L>(lazy: Lazy<L>): L => {
return evaluated;
};

export const partialEq: <T>(equality: PartialEq<T>) => PartialEq<Lazy<T>> =
partialEqFromProjection<LazyHkt>(force);
export const eq: <T>(equality: Eq<T>) => Eq<Lazy<T>> = eqFromProjection<
LazyHkt
>(force);
export const partialEq: <L, R>(
equality: PartialEq<L, R>,
) => PartialEq<Lazy<L>, Lazy<R>> = partialEqFromProjection<LazyHkt>(force);
export const eq: <L, R>(equality: Eq<L, R>) => Eq<Lazy<L>, Lazy<R>> =
eqFromProjection<LazyHkt>(force);
export const partialOrd: <T>(equality: PartialOrd<T>) => PartialOrd<Lazy<T>> =
partialOrdFromProjection<LazyHkt>(force);
export const ord: <T>(equality: Ord<T>) => Ord<Lazy<T>> = ordFromProjection<
LazyHkt
>(force);

export const partialEqUnary: PartialEqUnary<LazyHkt> = {
liftEq:
<L, R>(equality: (l: L, r: R) => boolean) =>
(l: Lazy<L>, r: Lazy<R>): boolean => equality(force(l), force(r)),
};

/**
* Wraps the evaluated value as a `Lazy`.
*
Expand Down
26 changes: 19 additions & 7 deletions src/map.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,15 @@ import { fromCmp, type Ord } from "./type-class/ord.ts";
import {
fromPartialEquality,
type PartialEq,
type PartialEqUnary,
} from "./type-class/partial-eq.ts";
import { fromPartialCmp, type PartialOrd } from "./type-class/partial-ord.ts";
import { semiGroupSymbol } from "./type-class/semi-group.ts";
import type { Traversable } from "./type-class/traversable.ts";

export const eq =
<K, V>(equality: PartialEq<V>) => (l: Map<K, V>, r: Map<K, V>): boolean => {
<K, L, R = L>(equality: PartialEq<L, R>) =>
(l: Map<K, L>, r: Map<K, R>): boolean => {
if (l.size !== r.size) {
return false;
}
Expand Down Expand Up @@ -73,12 +75,12 @@ export const cmp = <K, V>(ord: {
)(sortedL, sortedR);
};

export const partialEquality: <K, V>(
equality: PartialEq<V>,
) => PartialEq<Map<K, V>> = fromPartialEquality(eq);
export const equality: <K, V>(
equality: Eq<V>,
) => Eq<Map<K, V>> = fromEquality(eq);
export const partialEquality: <K, L, R = L>(
equality: PartialEq<L, R>,
) => PartialEq<Map<K, L>, Map<K, R>> = fromPartialEquality(eq);
export const equality: <K, L, R = L>(
equality: Eq<L, R>,
) => Eq<Map<K, L>, Map<K, R>> = fromEquality(eq);
export const partialOrd: <K, V>(ord: {
ordK: Ord<K>;
ordV: Ord<V>;
Expand All @@ -88,6 +90,16 @@ export const ord: <K, V>(ord: {
ordV: Ord<V>;
}) => Ord<Map<K, V>> = fromCmp(cmp);

/**
* The `PartialEqUnary` instance for `Map<K, _>`.
*/
export const partialEqUnary = <K>(): PartialEqUnary<Apply2Only<MapHkt, K>> => ({
liftEq:
<L, R = L>(equality: (l: L, r: R) => boolean) =>
(l: Map<K, L>, r: Map<K, R>): boolean =>
eq<K, L, R>({ eq: equality })(l, r),
});

export const isEmpty = <K, V>(m: Map<K, V>): boolean => m.size === 0;
export const size = <K, V>(m: Map<K, V>): number => m.size;

Expand Down
24 changes: 16 additions & 8 deletions src/option.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import { fromCmp, type Ord } from "./type-class/ord.ts";
import {
fromPartialEquality,
type PartialEq,
type PartialEqUnary,
} from "./type-class/partial-eq.ts";
import { fromPartialCmp, type PartialOrd } from "./type-class/partial-ord.ts";
import { semiGroupSymbol } from "./type-class/semi-group.ts";
Expand Down Expand Up @@ -171,19 +172,22 @@ export const toArray = <T>(opt: Option<T>): T[] => {
};

export const partialEquality =
<T>(equalityT: PartialEq<T>) =>
(optA: Option<T>, optB: Option<T>): boolean =>
<L, R = L>(equalityT: PartialEq<L, R>) =>
(optA: Option<L>, optB: Option<R>): boolean =>
(isNone(optA) && isNone(optB)) ||
(isSome(optA) && isSome(optB) && equalityT.eq(optA[1], optB[1]));
export const partialEq: <T>(equalityT: PartialEq<T>) => PartialEq<Option<T>> =
fromPartialEquality(partialEquality);
export const partialEq: <L, R = L>(
equalityT: PartialEq<L, R>,
) => PartialEq<Option<L>, Option<R>> = fromPartialEquality(partialEquality);
export const equality =
<T>(equalityT: Eq<T>) => (optA: Option<T>, optB: Option<T>): boolean =>
<L, R = L>(equalityT: Eq<L, R>) =>
(optA: Option<L>, optB: Option<R>): boolean =>
(isNone(optA) && isNone(optB)) ||
(isSome(optA) && isSome(optB) && equalityT.eq(optA[1], optB[1]));
export const eq: <T>(equalityT: Eq<T>) => Eq<Option<T>> = fromEquality(
equality,
);
export const eq: <L, R = L>(equalityT: Eq<L, R>) => Eq<Option<L>, Option<R>> =
fromEquality(
equality,
);
export const partialCmp =
<T>(order: PartialOrd<T>) =>
(l: Option<T>, r: Option<T>): Option<Ordering> => {
Expand Down Expand Up @@ -220,6 +224,10 @@ export const ord: <T>(order: Ord<T>) => Ord<Option<T>> = <T>(
order: Ord<T, T>,
) => fromCmp(cmp)(order);

export const partialEqUnary: PartialEqUnary<OptionHkt> = {
liftEq: (equality) => partialEquality({ eq: equality }),
};

/**
* Flattens the nested optional.
*
Expand Down
2 changes: 1 addition & 1 deletion src/range-q.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export const fromIterable =
acc: [...iterable].reduce<[T[], T]>(
(prev, curr) => {
const next = group.combine(prev[1], curr);
return [[...prev[0], next], next];
return [[...prev[0], next], next] as [T[], T];
},
[[], group.identity],
)[0],
Expand Down
Loading

0 comments on commit c6f2252

Please sign in to comment.