Skip to content

Instantly share code, notes, and snippets.

@jrsinclair
Created May 13, 2022 06:11
Show Gist options
  • Save jrsinclair/e4d9d73e9c7e5947de2612497f9cfb16 to your computer and use it in GitHub Desktop.
Save jrsinclair/e4d9d73e9c7e5947de2612497f9cfb16 to your computer and use it in GitHub Desktop.
Lenses that seem to work in Flow
// @flow strict-local
// Lenses
// ------------------------------------------------------------------------------------------------
export type LensInternal<S, T, A, B> = {
getVal: (S) => A,
setVal: (B, S) => T,
};
export type Lens<S, T, A, B> = {
(): LensInternal<S, T, A, B>,
compose: <C, D>(Lens<A, B, C, D>) => Lens<S, T, C, D>,
};
export const lens = <S, T, A, B>(getVal: (S) => A, setVal: (B, S) => T): Lens<S, T, A, B> => {
const lensFunc = () => ({ getVal, setVal });
lensFunc.compose = <C, D>(l: Lens<A, B, C, D>): Lens<S, T, C, D> => {
const { getVal: g2, setVal: s2 } = l();
return lens(
(x: S) => g2(getVal(x)),
(val: D, obj: S): T => setVal(s2(val, getVal(obj)), obj),
);
};
return lensFunc;
};
export const view = <S, T, A, B>(l: Lens<S, T, A, B>, obj: S): A => l().getVal(obj);
export const set = <S, T, A, B>(l: Lens<S, T, A, B>, val: B, obj: S): T => l().setVal(val, obj);
export const lensCompose = <S, T, A, B, C, D>(
l1: Lens<S, T, A, B>,
l2: Lens<A, B, C, D>,
): Lens<S, T, C, D> => l1.compose(l2);
type L<A, B> = Lens<A, A, B, B>;
export const propLens = <S, K: string, A, B>(
k: K,
): Lens<{ ...S, +[K]: A }, { ...S, +[K]: B }, A, B> =>
lens(
(s) => s[k],
(val, obj: S) => ({ ...obj, [k]: val }),
);
export const idxLens = <T>(idx: number): L<$ReadOnlyArray<T>, T> =>
lens(
(arr) => arr[idx],
(val, arr) => arr.slice(0, idx).concat([val]).concat(arr.slice(idx)),
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment