0

I achieved to implement Getter, Setter, Lens, LensAt (aka At in monocle) and LensOpt (aka Optional in monocle), However, I failed to generalize from Lens to Traversal and from Getter to Fold by adding an Applicative constraint:

const union = type => (tag, o) => (
  o[Symbol.toStringTag] = type,
  o.tag = tag.name || tag, o);

const record = (type, o) => (
  o[Symbol.toStringTag] = type.name || type, o);

const match = (tx, o) => o[tx.tag] (tx);

// Optics

const Optic = optic => record("Optic", {optic});

const arrLens = i =>
  Optic(map => f => xs =>
    map(x => arrSet(i) (x) (xs))
      (f(xs[i])));

const arrLensAt = i =>
  Optic(map => f => xs =>
    map(tx =>
      match(tx, {
        None: _ => arrDel(i) (xs),
        Some: ({some: x}) => arrIns(i) (x) (xs)
      })) (f(xs[i])));

const arrSetter = i => // TODO: maybe generalize with Settable constraint
  Optic(_ => f => xs =>
    idMap(x => arrSet(i) (x) (xs))
      (f(xs[i])));

const arrGetter = i =>
  Optic(map => f => xs =>
    map(id)
      (f(xs[i])));

const arrLensOpt = i => // also known as Optional for settings w/o sum types
  Optic(map => f => xs =>
    map(tx =>
      match(tx, {
        None: _ => xs,
        Some: ({some: x}) => arrSet(i) (x) (xs)
      })) (f(i < xs.length ? Some(xs[i]) : None)));

// Const type

const Const = _const => record("Const", {const: _const});
const constAp = append => ({const: f}) => ({const: x}) => Const(append(f) (x));
const constOf = empty => _ => Const(empty);
const constMap = _ => ({const: x}) => Const(x);

// Option type

const Option = union("Option");
const None = Option("None", {});
const Some = some => Option(Some, {some});

// Id type

const Id = id => record("Id", {id});
const idAp = ({id: f}) => ({id: x}) => Id(f(x));
const idOf = x => Id(x);
const idMap = f => ({id: x}) => Id(f(x));

// auxiliary functions

const _const = x => _ => x;

const arrSet = i => x => xs =>
  xs.slice(0, i)
    .concat(x, xs.slice(i + 1));

// MAIN

const xs = [1,2,3,4,5];

const tx = arrLensOpt(3).optic(constMap) (Const) (xs);
const ty = arrLensOpt(10).optic(constMap) (Const) (xs);
const tz = arrLensOpt(2).optic(idMap) (_const(Id(Some(333)))) (xs);


console.log(tx);
console.log(ty);
console.log(tz);

I have no idea how replacing Functor with Applicative allows me to combine several lenses or several getters respectively without changing the shape of the underlying structure (Optic(map => f => xs => ...) and its type. The Haskell/Scala optic libs I've found so far are rather complex and hard to follow.

const arrTraversal = i =>
  Optic(({ap, of}) => f => xs =>
    ap(???????)
      (f(xs[i])));

const arrFold = i =>
  Optic(({ap, of}) => f => xs =>
    ap(???????)
      (f(xs[i])));

I am not looking for a complete solution but rather for a promising approach.

  • A `Getter` is just a `Fold` that ignores it's Monoid instance, which is implicitly provided by `Const`. `Const` is only an Applicative, if its type parameter is a Monoid. –  Dec 17 '20 at 10:38
  • If we call `traverse(x => Const(f(x)))` and unwrap the result we get back `foldMap`, which is the minimal implementation of Foldable. I guess this is the machinery of the `Fold` optic. –  Dec 17 '20 at 10:39
  • The same holds for `Traversal` along with `Id`: `traverse(x => Id(f(x)))` gives back a functorial `map`. –  Dec 17 '20 at 10:42
  • If you have a constrained type like `type Getter s a = forall r . (a -> Const r a) -> s -> Const r a` and you just replace the constraint `type fold s a = forall r. Monoid r => (a -> Const r a) -> s -> Const r s` then you don't need another distinct implementation. The additional type constraint only enables different operations this type is involved in. –  Dec 17 '20 at 11:45
  • Additionally, you can compose a `Getter` with a `Fold` and get back a `Fold`, because both types only differ in their constraints and the result includes either both or the more specific constraint, if both form a hierarchy. This also holds for `Lens` and `Traverse` –  Dec 17 '20 at 11:51
  • Hopefully my rambling is helpful for somebody. –  Dec 17 '20 at 12:01
  • Could you provide types for your top level definitions? It's difficult to understand what your program is supposed to do. Oh, and Merry Christmas. =) – Aadit M Shah Dec 25 '20 at 04:56
  • @AaditMShah I'll try after the holidays. Thanks for the wishes! I don't know what Christmas means to you but rest assured that I only have the best in mind when I also wish you a Merry Christmas. –  Dec 25 '20 at 11:44

0 Answers0