From b8629d13211435d9b713897e3cc0c2bf315bda60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikuro=E3=81=95=E3=81=84=E3=81=AA?= Date: Thu, 21 Sep 2023 02:31:31 +0900 Subject: [PATCH] fix: Add docs and Improve filter func (#105) --- src/optical.ts | 76 ++++++++++++++++++++++++++++++++++++++----- src/optical/lens.ts | 25 ++++++++++++++ src/optical/prism.ts | 39 ++++++++++++++++++---- src/optical/setter.ts | 21 ++++++++++++ 4 files changed, 147 insertions(+), 14 deletions(-) diff --git a/src/optical.ts b/src/optical.ts index bfbe2f19..0f65f096 100644 --- a/src/optical.ts +++ b/src/optical.ts @@ -6,16 +6,36 @@ export * as Lens from "./optical/lens.js"; export * as Prism from "./optical/prism.js"; export * as Setter from "./optical/setter.js"; +/** + * Computation combinator with two-terminal pair. + * ```text + * |---------------| + * S ->| |-> A + * | Computation | + * T <-| |<- B + * |---------------| + * ``` + */ export type Optic = ( next: (sending: A) => (continuation: (returned: B) => R) => R, ) => (received: S) => (callback: (t: T) => R) => R; export type OpticSimple = Optic; +/** + * The identity combinator which does nothing. + */ export const identity = (): Optic => (x) => x; +/** + * Composes two computations. + * + * @param left - The second process. + * @param right - The first process. + * @returns The composed computation. + */ export const compose = (left: Optic) => (right: Optic): Optic => @@ -59,14 +79,55 @@ export const unwrap = }); export interface OpticCat { + /** + * Feeds the `Optic` and produces a new environment. + * + * @param o - The computation such as `Lens`, `Prism` and so on. + * @returns Modified environment. + */ readonly feed: (o: Optic) => OpticCat; + /** + * Modifies the value of the focused entry. + * + * @param modifier - The function which maps from the entry value to you desired. + * @returns Whole of data with the entry modified. + */ readonly over: (modifier: (a: A) => B) => T; + /** + * Overwrites the value of the focused entry. + * + * @param value - The value to be placed. + * @returns Whole of data with `value`. + */ readonly set: (value: B) => T; + /** + * Overwrites the value with the modifying computation. + * + * @param setter - The finish computation to add. + * @returns Whole of data with `setter`. + */ readonly setWith: (setter: Setter) => T; + /** + * Extracts the value of the focused entry. + * + * @returns Extracted value if exists. + */ readonly get: () => Option; + /** + * Extracts the value of the focused entry, or throws an error if not found. + * + * @returns Extracted value. + */ readonly unwrap: () => A; } +/** + * Creates a focused environment to compute about the part of the data structure. + * + * @param data - The data to be computed. + * @param o - The computation to use. + * @returns The modified environment. + */ export const focused = (data: S) => (o: Optic): OpticCat => ({ @@ -81,11 +142,10 @@ export const focused = }), }); -export const opticCat = (data: S): OpticCat => ({ - feed: (o) => focused(data)(compose(identity())(o)), - over: (modifier) => modifier(data), - set: (value) => value, - setWith: (setter) => setter(() => () => data)(data)((s) => s), - get: () => some(data), - unwrap: () => data, -}); +/** + * Creates an environment to compute about the data structure. + * + * @param data - The data to be computed. + * @returns The environment to compute. + */ +export const opticCat = (data: S): OpticCat => focused(data)(identity()); diff --git a/src/optical/lens.ts b/src/optical/lens.ts index 8949115d..c9cb82d7 100644 --- a/src/optical/lens.ts +++ b/src/optical/lens.ts @@ -10,6 +10,13 @@ import { type Optic } from "../optical.js"; +/** + * Creates a new `Lens` optic from the two functions. + * + * @param get - The extraction process. + * @param set - The overwrite process. + * @returns The computation to focus the data. + */ export const newLens = (get: (s: S) => A) => (set: (s: S) => (b: B) => T): Optic => @@ -18,6 +25,12 @@ export const newLens = (callback) => next(get(received))((b) => callback(set(received)(b))); +/** + * Focuses to the given index of array. + * + * @param index - The index of array to extract. + * @returns The lens for indexing. + */ export const nth = ( index: I, ): Optic => @@ -26,6 +39,12 @@ export const nth = >, V = O[K]>( k: K, ): Optic => @@ -39,6 +58,12 @@ export type Entries = K extends readonly [infer H, ...infer R] : never : [PropertyKey, unknown][]; +/** + * Focuses to the given keys of object. + * + * @param k - The keys array of object to extract. + * @returns The lens for indexing. + */ export const keys = < const K extends readonly PropertyKey[], O extends Readonly>, diff --git a/src/optical/prism.ts b/src/optical/prism.ts index c63e0801..58eca207 100644 --- a/src/optical/prism.ts +++ b/src/optical/prism.ts @@ -16,6 +16,13 @@ import type { Optic } from "../optical.js"; import { none, okOr, type Option, some } from "../option.js"; import { either, err, type Result } from "../result.js"; +/** + * Creates a new `Prism` optic from the two functions. + * + * @param upcast - The function which coerces the modified value to a partial type. + * @param downcast - The function which tries to coerces the source value. + * @returns The computation to focus the data. + */ export const newPrism = (upcast: (b: B) => T) => (downcast: (s: S) => Result): Optic => @@ -24,17 +31,37 @@ export const newPrism = (callback) => either(callback)((a: A) => next(a)((b) => callback(upcast(b))))(downcast(received)); +/** + * Creates a new `Prism` optic from the two functions, but `downcast` may return a `Option`. + * + * @param upcast - The function which coerces the modified value to a partial type. + * @param downcast - The function which tries to coerces the source value. + * @returns The computation to focus the data. + */ export const newPrismSimple = (upcast: (b: B) => S) => (downcast: (s: S) => Option): Optic => newPrism(upcast)((s) => okOr(s)(downcast(s))); +/** + * @returns The optic which matches nothing. Getting a value through this will throw an error. + */ export const unreachable = (): Optic => newPrism(absurd)(err); -export const only = (target: A): Optic => - newPrismSimple<[], A>(([]) => target)((x) => (x === target ? some(x) : none())); +/** + * Filters the value only if equals to `target`. + * + * @param target - For comparison. + * @returns The computation to filter the data. + */ +export const only = (target: A): Optic => + newPrismSimple((newValue) => newValue)((x) => (x === target ? some(x) : none())); -export const filter = - (init: A) => - (pred: (a: A) => boolean): Optic => - newPrismSimple<[], A>(([]) => init)((x) => (pred(x) ? some(x) : none())); +/** + * Filters the value only if satisfies `pred`. + * + * @param pred - Condition to filter. + * @returns The computation to filter the data. + */ +export const filter = (pred: (a: A) => boolean): Optic => + newPrismSimple((newValue) => newValue)((x) => (pred(x) ? some(x) : none())); diff --git a/src/optical/setter.ts b/src/optical/setter.ts index d729846a..6676ece2 100644 --- a/src/optical/setter.ts +++ b/src/optical/setter.ts @@ -13,8 +13,17 @@ import type { Optic } from "../optical.js"; import type { Functor } from "../type-class/functor.js"; import type { Monad } from "../type-class/monad.js"; +/** + * `Setter` is a `Optic` but does not allow to compose any computations more. + */ export type Setter = Optic; +/** + * Modifies going data as a terminal. + * + * @param mapper - The function to map the data going. + * @returns The mapping optic like `over`. + */ export const set = (mapper: (s: S) => T): Setter => () => @@ -22,6 +31,12 @@ export const set = (callback) => callback(mapper(received)); +/** + * Modifies data contained by `Functor` as a terminal. + * + * @param mapper - The function to map the data going. + * @returns The mapping optic. + */ export const setF = (f: Functor) => (mapper: (s: S) => T): Setter, Get1> => @@ -30,6 +45,12 @@ export const setF = (callback) => callback(f.map(mapper)(received)); +/** + * Modifies data contained by `Monad` as a terminal. + * + * @param mapper - The function to map the data going. + * @returns The mapping optic. + */ export const setM = (m: Monad) => (mapper: (s: S) => T): Setter, Get1> =>