Skip to content

Instantly share code, notes, and snippets.

@mormegil-cz
Created February 8, 2019 10:07
Show Gist options
  • Save mormegil-cz/f63ede60f7ffc7439330d5c1f3c81be6 to your computer and use it in GitHub Desktop.
Save mormegil-cz/f63ede60f7ffc7439330d5c1f3c81be6 to your computer and use it in GitHub Desktop.
Yoneda lemma examples implemented in C#
void Main()
{
ToYoneda(new[] {1, 2, -3, 4}.ToFunctor())
//.Alpha(x => x).Dump();
.Alpha(x => (x >= 0 ? "+" : "-")).Dump();
ToYoneda(new int?(3).ToFunctor())
.Alpha(x => (x >= 0 ? "+" : "-")).Dump();
FromYoneda(ToYoneda(new[] { 1, 2, -3, 4 }.ToFunctor())).Dump();
}
/// Generic functor interface
public interface IFunctor<T>
{
IFunctor<U> Select<U>(Func<T, U> f);
}
/// Representation using the function from Yoneda lemma
public interface IYonedaRepresentation<TElement>
{
/// (a -> x) -> F x
IFunctor<T> Alpha<T>(Func<TElement, T> f);
}
/// Implementation of the F x ~~~> (a -> x) -> F x direction
public static IYonedaRepresentation<T> ToYoneda<T>(IFunctor<T> original) => new YonedaRepresentation<T>(original);
/// Implementation of the (a -> x) -> F x ~~~> F x direction
public static IFunctor<T> FromYoneda<T>(IYonedaRepresentation<T> yoneda) => yoneda.Alpha(x => x);
/// Implementation of the Yoneda representation
public class YonedaRepresentation<TElement>
: IYonedaRepresentation<TElement>
{
private readonly IFunctor<TElement> original;
public YonedaRepresentation(IFunctor<TElement> original)
{
this.original = original;
}
public IFunctor<T> Alpha<T>(Func<TElement, T> f) => original.Select(f);
}
/// Helper extesions to easily get functor interface for common functors
public static class FunctorExtensions
{
public static MaybeFunctor<T> ToFunctor<T>(this T? nullable) where T : struct
=> MaybeFunctor<T>.FromNullable(nullable);
public static EnumerableFunctor<T> ToFunctor<T>(this IEnumerable<T> enumerable) => new EnumerableFunctor<T>(enumerable);
}
/// Implementation of the functor interface for the Maybe functor (nullable types)
public class MaybeFunctor<T> : IFunctor<T>
{
public static readonly MaybeFunctor<T> Empty = new MaybeFunctor<T>();
private readonly bool hasValue;
private readonly T value;
private MaybeFunctor()
{
}
public MaybeFunctor(T value)
{
this.hasValue = true;
this.value = value;
}
public static MaybeFunctor<U> FromNullable<U>(U? value) where U : struct
=> value.HasValue ? new MaybeFunctor<U>(value.GetValueOrDefault()) : MaybeFunctor<U>.Empty;
public IFunctor<U> Select<U>(Func<T, U> f) => hasValue ? new MaybeFunctor<U>(f(value)) : MaybeFunctor<U>.Empty;
private object ToDump() => new { hasValue, value };
}
/// Implementation of the Functor interface for enumerables
public class EnumerableFunctor<T> : IFunctor<T>
{
private readonly IEnumerable<T> list;
public EnumerableFunctor(IEnumerable<T> list)
{
this.list = list;
}
public IFunctor<U> Select<U>(Func<T, U> f) => new EnumerableFunctor<U>(list.Select(f));
private object ToDump() => list;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment