Ok, so I thought I had dropped this question for the night but then while I was just cleaning up formatting I realized that there was a little bit of a pattern here:
type Tag = LensTag | AffineTag | FoldTag;
export type Viewer<T extends Tag, S, A> = {
readonly tag: T;
readonly view: (s: S) => $<ToURI<T>, [A, never, never]>;
};
export type Modifier<S, A> = {
readonly modify: (modifyFn: (a: A) => A) => (s: S) => S;
};
export type Reviewer<S, A> = {
readonly review: (a: A) => S;
};
export type Optic<T extends Tag, S, A> = Viewer<T, S, A> & Modifier<S, A>;
export type Lens<S, A> = Optic<LensTag, S, A>;
export type Iso<S, A> = Lens<S, A> & Reviewer<S, A>;
export type AffineFold<S, A> = Optic<AffineTag, S, A>;
export type Prism<S, A> = AffineFold<S, A> & Reviewer<S, A>;
export type Fold<S, A> = Optic<FoldTag, S, A>;- Iso = Lens + Reviewer
- Prism = AffineFold + Reviewer
- ??? = Fold + Reviewer
So I decided to just implement a constructor for Fold + Reviewer and see what would happen..
/**
* Hacking around with nonsense
*/
export type Folderator<S, A> = Fold<S, A> & Reviewer<S, A>;
export function folderator<S, A>(
view: (s: S) => ReadonlyArray<A>,
review: (a: A) => S,
modify: (modifyFn: (a: A) => A) => (s: S) => S,
): Folderator<S, A> {
return { tag: FoldTag, view, review, modify };
}
const _array: Folderator<ReadonlyArray<any>, any> = folderator(
identity,
A.of,
A.map,
);
function arrFold<A>(): Folderator<ReadonlyArray<A>, A> {
return _array;
}
const _set: Folderator<ReadonlySet<any>, any> = folderator(
Array.from,
S.of,
S.map,
);
function setFold<A>(): Folderator<ReadonlySet<A>, A> {
return _set;
}After implementing folderator for array and set, I saw that the general "folderator" is pretty straightforward
function retraverse<U extends Kind>(
T: Traversable<U>,
of: <A, B = never, C = never, D = unknown, E = never>(
a: A,
) => $<U, [A, B, C], [D], [E]>,
): <A, B = never, C = never, D = unknown, E = never>() => Folderator<
$<U, [A, B, C], [D], [E]>,
A
> {
return () =>
folderator(
T.reduce((as, a) => [...as, a], A.empty()),
of,
T.map,
);
}So.. I'll probably look around for prior art for Fold + Reviewer (of which there likely isn't much since neither Larhooven lenses nor Profunctor optics construct the pattern with view/modify/review). If I find some cool, but otherwise I'll likely come up with a better name than folderator and work on a better compose that incorporates Reviewer composition.