Last active
July 20, 2019 17:53
-
-
Save b0urb4k1/28df132e2a913b9f6f38eb97bf9afa46 to your computer and use it in GitHub Desktop.
Functor and Applicative
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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