Skip to content

Instantly share code, notes, and snippets.

@benjamin-hodgson
Created March 19, 2018 16:08
Show Gist options
  • Save benjamin-hodgson/8c7ddf2356509a0177394e81384ddfec to your computer and use it in GitHub Desktop.
Save benjamin-hodgson/8c7ddf2356509a0177394e81384ddfec to your computer and use it in GitHub Desktop.
Composable lens hierarchy using default interface implementations
interface ISetter<in S, out T, out A, in B>
{
T Rewrite(S oldContainer, Func<A, B> rewriter);
}
interface IFold<in S, out A>
{
R Aggregate<R>(S container, R seed, Func<R, A, R> aggregator);
}
interface ITraversal<in S, out T, out A, in B> : ISetter<S, T, A, B>, IFold<S, A>
{
T SetList(S oldContainer, IEnumerable<B> newChildren);
T Rewrite(S oldContainer, Func<A, B> rewriter)
=> SetList(oldContainer, this.GetList(container).Select(rewriter));
}
interface IGetter<in S, out A> : IFold<S, A>
{
A Get(S container);
R Aggregate<R>(S container, R seed, Func<R, A, R> aggregator)
=> aggregator(seed, Get(container));
}
interface ILens<in S, out T, out A, in B> : ITraversal<S, T, A, B>, IGetter<S, A>
{
T Set(S oldContainer, B newValue);
T SetList(S oldContainer, IEnumerable<B> newChildren)
=> Set(oldContainer, newChildren.Single());
}
interface IReview<out T, in B>
{
T Inject(B value);
}
interface IPrism<in S, out T, out A, in B> : IReview<T, B>, ITraversal<S, T, A, B>
{
IEither<T, A> TryGet(S value);
R Aggregate<R>(S container, R seed, Func<R, A, R> aggregator)
{
var result = TryGet(container);
if (result.IsLeft)
{
return seed;
}
return aggregator(seed, result.Right);
}
T SetList(S oldContainer, IEnumerable<B> newChildren)
=> Inject(newChildren.Single());
}
interface IEither<out T, out U>
{
R Match<R>(Func<T, R> ifLeft, Func<U, R> ifRight);
}
static class Lens
{
public static ILens<S, T, U, V> _(this ILens<S, T, A, B> lens1, ILens<A, B, U, V> lens2);
public static ITraversal<S, T, U, V> _(this ITraversal<S, T, A, B> traversal1, ITraversal<A, B, U, V> traversal2);
public static IGetter<S, U> _(this IGetter<S, A> getter1, IGetter<A, U> getter2);
public static ISetter<S, T, U, V> _(this ISetter<S, T, A, B> setter1, ISetter<A, B, U, V> setter2);
public static IFold<S, U> _(this IFold<S, A> fold1, IFold<A, U> fold2);
public static IPrism<S, T, U, V> _(this IPrism<S, T, A, B> prism1, this IPrism<A, B, U, V> prism2);
public static IReview<T, V> _(this IReview<T, B> review1, IReview<B, V> review2);
public static A Get<S, A>(this S container, IGetter<S, A> getter);
public static T Set<S, T, A, B>(this S container, ISetter<S, T, A, B> setter, B newValue);
public static ImmutableList<A> GetList<S, A>(this S container, IFold<S, A> fold);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment