Skip to content

Instantly share code, notes, and snippets.

@b0urb4k1
Last active July 20, 2019 17:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save b0urb4k1/28df132e2a913b9f6f38eb97bf9afa46 to your computer and use it in GitHub Desktop.
Save b0urb4k1/28df132e2a913b9f6f38eb97bf9afa46 to your computer and use it in GitHub Desktop.
Functor and Applicative
using System;
using System.Linq;
using static MeditationHelper.Prelude;
namespace MeditationHelper
{
public static class Prelude
{
public static Func<T1, R> fun<T1, R>(Func<T1, R> f) => f;
public static Func<T1, T2, R> fun<T1, T2, R>(Func<T1, T2, R> f) => f;
}
public static class Functor_Maybe_Tuple
{
public static (bool fail, T2 result) map<T1, T2>(this (bool, T1) x, Func<T1, T2> f) =>
x switch
{ (true, _) => (true, default(T2))
, (false, var v) => (false, f(v))
};
}
public static class Applicative_Maybe_Tuple
{
public static (bool fail, T) lift<T>(T value) => (false, value);
public static (bool fail, R) apply<T, R>(this (bool, Func<T, R>) applicative, (bool, T) value) =>
applicative switch
{ (true, _) => (true, default(R))
, (false, var f) => value.map(f)
};
}
public interface IValidation<T> {}
public sealed class Errors<T> : IValidation<T>
{
private Errors(string[] errors)
{
this.errors = errors;
}
public static Errors<T> Create(string[] e) =>
new Errors<T>(e);
public static Errors<T> Create(string e) =>
new Errors<T>(new [] {e});
public string[] errors;
public void Deconstruct(out string[] errors) => errors = this.errors;
}
public sealed class Value<T> : IValidation<T>
{
private Value(T value)
{
this.value = value;
}
public static Value<T> Create(T value) =>
new Value<T>(value);
public T value;
public void Deconstruct(out T value) => value = this.value;
}
public static class Functor_Validation
{
public static IValidation<R> map<T, R>(this IValidation<T> value, Func<T, R> fn) =>
value switch
{ Errors<T>(var e) => Errors<R>.Create(e) as IValidation<R>
, Value<T>(var v) => Value<R>.Create(fn(v)) as IValidation<R>
, null => Errors<R>.Create("null provided") as IValidation<R>
, {} => throw new TypeAccessException()
};
public static IValidation<Func<T2, R>> map<T1, T2, R>(this IValidation<T1> value, Func<T1, T2, R> fn) =>
value switch
{ Errors<T1>(var e) => Errors<Func<T2, R>>.Create(e) as IValidation<Func<T2, R>>
, Value<T1>(var v) => Value<Func<T2, R>>.Create((T2 x) => fn(v, x)) as IValidation<Func<T2, R>>
, {} => throw new TypeAccessException()
};
}
public static class Applicative_Validation
{
public static IValidation<T> lift<T>(T value) => Value<T>.Create(value);
public static IValidation<R> apply<T, R>(this IValidation<Func<T, R>> applicative, IValidation<T> value) =>
(applicative, value) switch
{ (Errors<Func<T, R>>(var e1), Errors<T>(var e2)) => Errors<R>.Create(e1.Concat(e2).ToArray())
, (Errors<Func<T, R>>(var e1), Value<T> _) => Errors<R>.Create(e1)
, (Value<Func<T, R>> _, Errors<T>(var e2)) => Errors<R>.Create(e2)
, (Value<Func<T, R>>(var f), Value<T> _) => value.map(f)
, {} => throw new TypeAccessException()
};
public static IValidation<Func<T2, R>> apply<T1, T2, R>(this IValidation<Func<T1, T2, R>> applicative, IValidation<T1> value) =>
(applicative, value) switch
{ (Errors<Func<T1, T2, R>>(var e1), Errors<T1>(var e2)) => Errors<Func<T2, R>>.Create(e1.Concat(e2).ToArray())
, (Errors<Func<T1, T2, R>>(var e1), Value<T1> _) => Errors<Func<T2, R>>.Create(e1)
, (Value<Func<T1, T2, R>> _, Errors<T1>(var e2)) => Errors<Func<T2, R>>.Create(e2)
, (Value<Func<T1, T2, R>>(var f), Value<T1> _) => value.map(f)
, {} => throw new TypeAccessException()
};
}
class Program
{
static void Main(string[] args)
{
var x = Value<int>.Create(1);
var y = Value<int>.Create(2);
var e1 = Errors<int>.Create("foo");
var e2 = Errors<int>.Create("bar");
var createTuple =
Applicative_Validation.lift(fun((int x, int y) => (x, y)));
var resOk = createTuple.apply(x).apply(y);
var resFail1 = createTuple.apply(x).apply(e1);
var resFail2 = createTuple.apply(e1).apply(y);
var resFail3 = createTuple.apply(e1).apply(e2);
Console.WriteLine("Hello World!");
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment