Init Scripts in new repo
This commit is contained in:
17
Functional/Cache.cs
Normal file
17
Functional/Cache.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
namespace SJK.Functional;
|
||||
|
||||
public class Cache<T> where T : class
|
||||
{
|
||||
private T? _cache;
|
||||
private Func<T> _provider;
|
||||
private readonly Func<T, bool>? _isvalid;
|
||||
|
||||
public Cache(Func<T> provider, Func<T, bool>? isvalid = null)
|
||||
{
|
||||
_provider = provider;
|
||||
_isvalid = isvalid;
|
||||
}
|
||||
public bool IsCached() => _cache is not null;
|
||||
public T Value => _cache is null || (_isvalid is not null && !_isvalid(_cache)) ? _cache = _provider() : _cache;
|
||||
|
||||
}
|
||||
14
Functional/IEither.cs
Normal file
14
Functional/IEither.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
namespace SJK.Functional;
|
||||
|
||||
public interface IEither<TLeft, TRight>
|
||||
{
|
||||
IEither<TNewLeft, TRight> MapLeft<TNewLeft>(Func<TLeft, TNewLeft> mapping);
|
||||
IEither<TLeft, TNewRight> MapRight<TNewRight>(Func<TRight, TNewRight> mapping);
|
||||
TLeft Reduce(Func<TRight, TLeft> mapping);
|
||||
(TLeft?, TRight?) Deconstruct();
|
||||
TResult Match<TResult>(Func<TLeft, TResult> left, Func<TRight, TResult> right);
|
||||
void Match(Action<TLeft> left, Action<TRight> right);
|
||||
IEither<TLeft, T2> Bind<T2>(Func<TRight, IEither<TLeft, T2>> value);
|
||||
bool IsRight();
|
||||
bool IsLeft() => !IsRight();
|
||||
}
|
||||
51
Functional/IOption.cs
Normal file
51
Functional/IOption.cs
Normal file
@@ -0,0 +1,51 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace SJK.Functional;
|
||||
public interface IOption<T> : IEquatable<IOption<T>>
|
||||
{
|
||||
/// <summary>
|
||||
/// Applies a function to the contained value if it exists (is not None), otherwise applies a default function.
|
||||
/// </summary>
|
||||
/// <param name="onSome">Function to apply if the option contains a value.</param>
|
||||
/// <param name="onNone">Function to apply if the option does not contain a value.</param>
|
||||
/// <returns>The result of applying either the onSome or onNone function.</returns>
|
||||
TResult Match<TResult>(Func<T, TResult> onSome, Func<TResult> onNone);
|
||||
void Match(Action<T> onSome,Action onNone);
|
||||
|
||||
/// <summary>
|
||||
/// Chains operations on the contained value using a function that returns an option.
|
||||
/// </summary>
|
||||
/// <param name="f">A function that takes the contained value and returns an option.</param>
|
||||
/// <returns>An option resulting from applying the function f to the contained value.</returns>
|
||||
IOption<TResult> Bind<TResult>(Func<T, IOption<TResult>> f);
|
||||
|
||||
/// <summary>
|
||||
/// Maps a function over the contained value if it exists (is not None).
|
||||
/// </summary>
|
||||
/// <param name="f">The function to apply to the contained value.</param>
|
||||
/// <returns>An option containing the result of applying f to the contained value.</returns>
|
||||
IOption<TResult> Map<TResult>(Func<T, TResult> f);
|
||||
|
||||
/// <summary>
|
||||
/// Returns the contained value if it exists (is not None), otherwise returns the provided default value.
|
||||
/// </summary>
|
||||
/// <param name="aDefault">The default value to return if the option does not contain a value.</param>
|
||||
/// <returns>The contained value or the default value.</returns>
|
||||
T Or(T aDefault);
|
||||
|
||||
/// <summary>
|
||||
/// Returns the contained value if it exists (is not None), otherwise calls the provided default function.
|
||||
/// </summary>
|
||||
/// <param name="aDefault">The default value to return if the option does not contain a value.</param>
|
||||
/// <returns>The contained value or the default value.</returns>
|
||||
T Or(Func<T> aDefault);
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the option contains a value (is not None) and outputs it if true.
|
||||
/// </summary>
|
||||
/// <param name="value">An out parameter that will be assigned the contained value if it exists.</param>
|
||||
/// <returns>true if the option contains a value; false otherwise.</returns>
|
||||
bool HasValue([NotNullWhen(true)]out T? value);
|
||||
// [Obsolete]
|
||||
bool HasValue();
|
||||
}
|
||||
42
Functional/Left.cs
Normal file
42
Functional/Left.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
namespace SJK.Functional;
|
||||
|
||||
public sealed class Left<TLeft, TRight> : IEither<TLeft, TRight>
|
||||
{
|
||||
private readonly TLeft _value;
|
||||
public Left(TLeft value){
|
||||
this._value = value;
|
||||
}
|
||||
|
||||
|
||||
public IEither<TLeft, T2> Bind<T2>(Func<TRight, IEither<TLeft, T2>> value)
|
||||
{
|
||||
return new Left<TLeft,T2>(_value);
|
||||
}
|
||||
|
||||
public (TLeft?, TRight?) Deconstruct()=>(_value,default(TRight));
|
||||
|
||||
public bool IsRight() => true;
|
||||
|
||||
public IEither<TNewLeft, TRight> MapLeft<TNewLeft>(Func<TLeft, TNewLeft> mapping)
|
||||
=> new Left<TNewLeft,TRight>(mapping(this._value));
|
||||
|
||||
public IEither<TLeft, TNewRight> MapRight<TNewRight>(Func<TRight, TNewRight> mapping)
|
||||
=> new Left<TLeft,TNewRight>(this._value);
|
||||
|
||||
|
||||
public TResult Match<TResult>(Func<TLeft, TResult> left, Func<TRight, TResult> right)
|
||||
{
|
||||
return left(_value);
|
||||
}
|
||||
|
||||
public void Match(Action<TLeft> left, Action<TRight> right)
|
||||
{
|
||||
left(_value);
|
||||
}
|
||||
|
||||
public TLeft Reduce(Func<TRight, TLeft> mapping)=> _value;
|
||||
public override string ToString()
|
||||
{
|
||||
return $"Left<{typeof(TLeft).Name}> with Value {_value}";
|
||||
}
|
||||
}
|
||||
31
Functional/None.cs
Normal file
31
Functional/None.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace SJK.Functional;
|
||||
|
||||
public sealed class None<T> : IOption<T>
|
||||
{
|
||||
|
||||
public static None<T> Of() => new();
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public TResult Match<TResult>(Func<T, TResult> _, Func<TResult> onNone) =>
|
||||
onNone();
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void Match(Action<T> onSome, Action onNone) => onNone();
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public IOption<TResult> Bind<TResult>(Func<T, IOption<TResult>> f) => new None<TResult>();
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public IOption<TResult> Map<TResult>(Func<T, TResult> f) => new None<TResult>();
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public T Or(T aDefault) => aDefault;
|
||||
public T Or(Func<T> aDefault)=>aDefault();
|
||||
public bool HasValue([NotNullWhen(true)]out T? value) => (value = default) is not null && false;
|
||||
public bool HasValue() => false;
|
||||
public override string ToString()
|
||||
{
|
||||
return nameof(None<T>);
|
||||
}
|
||||
|
||||
public bool Equals(IOption<T>? other)=> other is None<T>;
|
||||
}
|
||||
87
Functional/OptionExtensions.cs
Normal file
87
Functional/OptionExtensions.cs
Normal file
@@ -0,0 +1,87 @@
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace SJK.Functional;
|
||||
|
||||
public static class OptionExtensions
|
||||
{
|
||||
public static IEnumerable<TResult> Match<T, TResult>(this IEnumerable<IOption<T>> values, Func<T, TResult> onSome, Func<TResult> onNone)
|
||||
{
|
||||
foreach (var item in values)
|
||||
{
|
||||
yield return item.Match(onSome, onNone);
|
||||
}
|
||||
}
|
||||
// public static IOption<T> GetValue<Tkey, T>(this IDictionary<Tkey, T> value, Tkey key) where Tkey : notnull
|
||||
// {
|
||||
// if (value.TryGetValue(key, out var v))
|
||||
// {
|
||||
// return v.ToOption();
|
||||
// }
|
||||
// return None<T>.Of();
|
||||
// }
|
||||
public static IOption<T> GetValue<Tkey, T>(this IReadOnlyDictionary<Tkey, T> value, Tkey key) where Tkey : notnull
|
||||
{
|
||||
if (value.TryGetValue(key, out var v))
|
||||
{
|
||||
return v.ToOption();
|
||||
}
|
||||
return None<T>.Of();
|
||||
}
|
||||
public static IOption<T> OrElse<T>(this IOption<T> option, Func<IOption<T>> fallback)
|
||||
{
|
||||
return option.Match(
|
||||
some => option,
|
||||
() => fallback()
|
||||
);
|
||||
}
|
||||
public static IOption<TResult> BindUsing<TDisposable, TResult>(
|
||||
this IOption<TDisposable> option,
|
||||
Func<TDisposable, IOption<TResult>> func)
|
||||
where TDisposable : IDisposable
|
||||
{
|
||||
return option.Match(
|
||||
some =>
|
||||
{
|
||||
using (some) return func(some);
|
||||
},
|
||||
() => None<TResult>.Of()
|
||||
);
|
||||
}
|
||||
|
||||
public static IOption<T> ToOption<T>(this T? value) => value != null ? Some<T>.Of(value) : None<T>.Of();
|
||||
[StackTraceHidden]
|
||||
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static T OrThrow<T, TEx>(this IOption<T> option, Func<TEx> exceptionFactory) where TEx : Exception
|
||||
{
|
||||
if (option.HasValue(out var value))
|
||||
return value;
|
||||
|
||||
throw exceptionFactory();
|
||||
}
|
||||
public static IEither<L, R> ToEither<Tvalue, L, R>(this Tvalue value, Func<Tvalue, bool> isSuccess, Func<R> ok, Func<Tvalue, L> err)
|
||||
{
|
||||
return isSuccess(value) ? new Right<L, R>(ok()) : new Left<L, R>(err(value));
|
||||
}
|
||||
public static IEither<L, R> ToEither<Tvalue, L, R>(this Tvalue value, Tvalue successValue, Func<R> ok, Func<Tvalue, L> err)
|
||||
{
|
||||
return value.ToEither(e => e.Equals(successValue), ok, err);
|
||||
}
|
||||
// public static IEnumerable<IOption<T>> ToOptions<T>(this IEnumerable<T> value) => value.Select(thing => thing.ToOption());
|
||||
public static Some<T> ToSome<T>(this T value) where T : notnull => Some<T>.Of(value);
|
||||
public static void IfSome<T>(this IOption<T> value, Action<T> onSome) => value.Match(onSome, () => { });
|
||||
public static void IfNone<T>(this IOption<T> value, Action onNone) => value.Match(_ => { }, onNone);
|
||||
|
||||
public static T Or<T>(this IOption<T> value, Func<T> @default) => value.Or(@default());
|
||||
public static IEnumerable<T> OnlySomes<T>(this IEnumerable<IOption<T>> options)
|
||||
{
|
||||
foreach (var item in options)
|
||||
{
|
||||
if (item.HasValue(out var item2))
|
||||
yield return item2;
|
||||
}
|
||||
}
|
||||
// public static None<T> ToNone<T>(this T value) => None<T>.Of();
|
||||
|
||||
public static Option<T> ToStructOption<T>(this IOption<T> option) => option.HasValue(out var value) ? Option<T>.Some(value) : Option<T>.None;
|
||||
public static IOption<T> ToClassOption<T>(this Option<T> option) => option.HasValue ? option.Value.ToOption() : None<T>.Of();
|
||||
}
|
||||
40
Functional/OptionalStruct.cs
Normal file
40
Functional/OptionalStruct.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace SJK.Functional;
|
||||
|
||||
public struct Option<T> : IEquatable<Option<T>>
|
||||
{
|
||||
private readonly T? _value;
|
||||
[MemberNotNullWhen(true, nameof(_value))]
|
||||
public bool HasValue { get; }
|
||||
public static Option<T> None => new(default, false);
|
||||
public static Option<T> Some(T value) => new(value, true);
|
||||
private Option(T? value, bool hasValue)
|
||||
{
|
||||
Debug.Assert(!(value is null && hasValue), "Can not create an option with a null value had say it has one");
|
||||
|
||||
_value = value;
|
||||
HasValue = hasValue;
|
||||
}
|
||||
public T? Value => HasValue ? _value : throw new InvalidOperationException("Can not retrive value when there is no value.");
|
||||
|
||||
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public TResult Match<TResult>(Func<T, TResult> some, Func<TResult> none) => HasValue ? some(_value) : none();
|
||||
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Option<TResult> Map<TResult>(Func<T, TResult> f) => HasValue ? Option<TResult>.Some(f(_value)) : Option<TResult>.None;
|
||||
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Option<TResult> Bind<TResult>(Func<T, Option<TResult>> f) => HasValue ? f(_value) : Option<TResult>.None;
|
||||
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public T OrDefault(T value) => HasValue ? _value : value;
|
||||
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public T Or(Func<T> factory) => HasValue ? _value : factory();
|
||||
|
||||
public override bool Equals([NotNullWhen(true)] object? obj) => obj is Option<T> other && Equals(other);
|
||||
|
||||
public bool Equals(Option<T> other) => (HasValue == other.HasValue) && (!HasValue || EqualityComparer<T>.Default.Equals(_value, other._value));
|
||||
|
||||
public override int GetHashCode() => HasValue ? EqualityComparer<T>.Default.GetHashCode(_value) : 0;
|
||||
public override string ToString() => HasValue ? $"Some({_value})" : $"None<{typeof(T).Name}>()";
|
||||
}
|
||||
38
Functional/Right.cs
Normal file
38
Functional/Right.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
namespace SJK.Functional;
|
||||
|
||||
public sealed class Right<TLeft, TRight> : IEither<TLeft, TRight>
|
||||
{
|
||||
private readonly TRight _value;
|
||||
public Right(TRight value){
|
||||
this._value = value;
|
||||
}
|
||||
public (TLeft?, TRight?) Deconstruct()=>(default(TLeft),_value);
|
||||
public IEither<TNewLeft, TRight> MapLeft<TNewLeft>(Func<TLeft, TNewLeft> mapping)
|
||||
=> new Right<TNewLeft,TRight>(this._value);
|
||||
|
||||
public IEither<TLeft, TNewRight> MapRight<TNewRight>(Func<TRight, TNewRight> mapping)
|
||||
=> new Right<TLeft,TNewRight>(mapping(this._value));
|
||||
|
||||
public TLeft Reduce(Func<TRight, TLeft> mapping)=> mapping(this._value);
|
||||
public override string ToString()
|
||||
{
|
||||
return $"Right<{typeof(TRight).Name}> with Value {_value}";
|
||||
}
|
||||
|
||||
public TResult Match<TResult>(Func<TLeft, TResult> left, Func<TRight, TResult> right)
|
||||
{
|
||||
return right(_value);
|
||||
}
|
||||
|
||||
public void Match(Action<TLeft> left, Action<TRight> right)
|
||||
{
|
||||
right(_value);
|
||||
}
|
||||
|
||||
public IEither<TLeft, T2> Bind< T2>(Func<TRight, IEither<TLeft, T2>> value)
|
||||
{
|
||||
return value(_value);
|
||||
}
|
||||
|
||||
public bool IsRight() => false;
|
||||
}
|
||||
44
Functional/Some.cs
Normal file
44
Functional/Some.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace SJK.Functional;
|
||||
|
||||
public class Some<T> : IOption<T>
|
||||
{
|
||||
private readonly T _data;
|
||||
|
||||
private Some(T data)
|
||||
{
|
||||
_data = data;
|
||||
}
|
||||
public ref readonly T Value => ref _data;
|
||||
public static Some<T> Of(T data) => new(data);
|
||||
// [MethodImpl(MethodImplOptions.AggressiveInlining)]//TODO see if these inporve perfomce in gernral cases
|
||||
public TResult Match<TResult>(Func<T, TResult> onSome, Func<TResult> _) =>
|
||||
onSome(_data);
|
||||
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public IOption<TResult> Bind<TResult>(Func<T, IOption<TResult>> f) => f(_data);
|
||||
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public IOption<TResult> Map<TResult>(Func<T, TResult> f) => new Some<TResult>(f(_data));
|
||||
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public T Or(T _) => _data;
|
||||
public T Or(Func<T> aDefault) => _data;
|
||||
public bool HasValue([NotNullWhen(true)]out T? value) => (value = _data) is not null;
|
||||
|
||||
public bool HasValue() => true;
|
||||
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void Match(Action<T> onSome, Action onNone) => onSome(_data);
|
||||
public override string ToString()
|
||||
{
|
||||
return nameof(Some<T>)+": "+ _data;
|
||||
}
|
||||
|
||||
public bool Equals(IOption<T>? other)
|
||||
{
|
||||
if (other is Some<T> some){
|
||||
return _data!.Equals(some._data);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
7
Functional/Tuple.cs
Normal file
7
Functional/Tuple.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace SJK.Functional;
|
||||
|
||||
public static class TupleExtensions
|
||||
{
|
||||
public static (T1, T2) ToTuple<T1, T2>(this T1 first, T2 second) => (first, second);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user