using System;
using System.Collections.Immutable;

public interface ILens<Hole, Whole> {
  Hole value { get; }
  Whole Update(Func<Hole, Hole> update);
}

public static class LensExtensionMethods {
  public static Whole Update<Hole, Whole>(this ILens<Hole, Whole> lens, Hole newHole)
    => lens.Update(oldHole => newHole);

  public static Whole Cons<T, Whole>(this T value, ILens<ImmutableList<T>, Whole> lens)
    => lens.Update(oldHole => value.Cons(oldHole));

  public static ILens<string, Whole> ChainLens<Whole>(this string hole, System.Func<string, Whole> wrap) => new LeafLens<string, Whole>(wrap: wrap, oldHole: hole);

  public static ILens<Func<GraphemeCluster,bool>, Whole> ChainLens<Whole>(this Func<GraphemeCluster,bool> hole, System.Func<Func<GraphemeCluster,bool>, Whole> wrap) => new LeafLens<Func<GraphemeCluster,bool>, Whole>(wrap: wrap, oldHole: hole);

  public class FocusableLeaf<T> {
    private readonly T value;
    public FocusableLeaf(T value) { this.value = value; }
    public LeafLens<T, Whole> ChainLens<Whole>(Func<T, Whole> wrap)
      => new LeafLens<T, Whole>(wrap: wrap, oldHole: value);
  }
}