Refactored Option<T> to have opertator lifting and removed ref struct for now.
All checks were successful
Build NuGet / build (push) Successful in 1m43s

This commit is contained in:
2026-08-07 12:58:11 -04:00
parent 1d53af4b46
commit 262b76c4d5
13 changed files with 1123 additions and 262 deletions

188
.vscode/settings.json vendored
View File

@@ -1 +1,187 @@
{} {
"[csharp]": {
"editor.codeActionsOnSave": {
"source.addMissingImports": "explicit",
"source.fixAll": "explicit",
"source.organizeImports": "explicit"
},
"editor.formatOnPaste": true,
"editor.formatOnSave": true,
"editor.formatOnType": false
},
"emeraldwalk.runonsave": {
"commands": [
{
// run `clang-format` on Godot shader files when saving
"match": "\\.gdshader|\\.gdshaderinc$",
"cmd": "clang-format -i '${file}'"
}
]
},
"csharp.debug.justMyCode": false,
"csharp.debug.suppressJITOptimizations": true,
"csharp.semanticHighlighting.enabled": true,
"dotnet.backgroundAnalysis.analyzerDiagnosticsScope": "fullSolution",
"dotnet.backgroundAnalysis.compilerDiagnosticsScope": "fullSolution",
"dotnet.completion.showCompletionItemsFromUnimportedNamespaces": true,
"dotnet.enableXamlTools": false,
"dotnet.formatting.organizeImportsOnFormat": true,
"dotnet.preferCSharpExtension": true,
"dotnet.server.useOmnisharp": false, // You decide
"dotnetAcquisitionExtension.enableTelemetry": false,
"editor.semanticHighlighting.enabled": true,
// C# doc comment colorization gets lost with semantic highlighting, but we
// need semantic highlighting for proper syntax highlighting with record
// shorthand.
//
// Here's a workaround for doc comment highlighting from
// https://github.com/OmniSharp/omnisharp-vscode/issues/3816
"editor.tokenColorCustomizations": {
"[*]": {
// Themes that don't include the word "Dark" or "Light" in them.
// These are some bold colors that show up well against most dark and
// light themes.
//
// Change them to something that goes well with your preferred theme :)
"textMateRules": [
{
"scope": "comment.documentation",
"settings": {
"foreground": "#0091ff"
}
},
{
"scope": "comment.documentation.attribute",
"settings": {
"foreground": "#8480ff"
}
},
{
"scope": "comment.documentation.cdata",
"settings": {
"foreground": "#0091ff"
}
},
{
"scope": "comment.documentation.delimiter",
"settings": {
"foreground": "#aa00ff"
}
},
{
"scope": "comment.documentation.name",
"settings": {
"foreground": "#ef0074"
}
}
]
},
"[*Dark*]": {
// Themes that include the word "Dark" in them.
"textMateRules": [
{
"scope": "comment.documentation",
"settings": {
"foreground": "#608B4E"
}
},
{
"scope": "comment.documentation.attribute",
"settings": {
"foreground": "#C8C8C8"
}
},
{
"scope": "comment.documentation.cdata",
"settings": {
"foreground": "#E9D585"
}
},
{
"scope": "comment.documentation.delimiter",
"settings": {
"foreground": "#808080"
}
},
{
"scope": "comment.documentation.name",
"settings": {
"foreground": "#569CD6"
}
}
]
},
"[*Light*]": {
// Themes that include the word "Light" in them.
"textMateRules": [
{
"scope": "comment.documentation",
"settings": {
"foreground": "#008000"
}
},
{
"scope": "comment.documentation.attribute",
"settings": {
"foreground": "#282828"
}
},
{
"scope": "comment.documentation.cdata",
"settings": {
"foreground": "#808080"
}
},
{
"scope": "comment.documentation.delimiter",
"settings": {
"foreground": "#808080"
}
},
{
"scope": "comment.documentation.name",
"settings": {
"foreground": "#808080"
}
}
]
}
},
"explorer.fileNesting.enabled": true,
"explorer.fileNesting.expand": false,
"explorer.fileNesting.patterns": {
"*": "$(capture).import, $(capture).uid"
},
"markdownlint.config": {
// Allow non-unique heading names so we don't break the changelog.
"MD024": false,
// Allow html in markdown.
"MD033": false
},
"markdownlint.ignore": [
"**/LICENSE"
],
"omnisharp.enableEditorConfigSupport": true,
"omnisharp.enableMsBuildLoadProjectsOnDemand": false,
"omnisharp.maxFindSymbolsItems": 3000,
"omnisharp.useModernNet": false,
// Remove these if you're happy with your terminal profiles.
"terminal.integrated.defaultProfile.windows": "Git Bash",
"terminal.integrated.profiles.windows": {
"Command Prompt": {
"icon": "terminal-cmd",
"path": [
"${env:windir}\\Sysnative\\cmd.exe",
"${env:windir}\\System32\\cmd.exe"
]
},
"Git Bash": {
"icon": "terminal",
"source": "Git Bash"
},
"PowerShell": {
"icon": "terminal-powershell",
"source": "PowerShell"
}
}
}

View File

@@ -1,17 +1,17 @@
namespace SJK.Functional; namespace SJK.Functional;
// [Obsolete]
// public class Cache<T> where T : class
// {
// private T? _cache;
// private Func<T> _provider;
// private readonly Func<T, bool>? _isvalid;
public class Cache<T> where T : class // public Cache(Func<T> provider, Func<T, bool>? isvalid = null)
{ // {
private T? _cache; // _provider = provider;
private Func<T> _provider; // _isvalid = isvalid;
private readonly Func<T, bool>? _isvalid; // }
// public bool IsCached() => _cache is not null;
// public T Value => _cache is null || (_isvalid is not null && !_isvalid(_cache)) ? _cache = _provider() : _cache;
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;
}

View File

@@ -1,3 +1,5 @@
using System.Diagnostics.CodeAnalysis;
namespace SJK.Functional; namespace SJK.Functional;
public interface IEither<TLeft, TRight> public interface IEither<TLeft, TRight>
@@ -12,3 +14,140 @@ public interface IEither<TLeft, TRight>
bool IsRight(); bool IsRight();
bool IsLeft() => !IsRight(); bool IsLeft() => !IsRight();
} }
// public class test
// {
// public static void Main()
// {
// var res = TestEither();
// if (res.Ok)
// {
// }
// res.Match(success => Option.Some(success), error => Option.None<int>());
// }
// public static Result<int,bool> TestEither()
// {
// return new Result<int,bool>();
// }
// }
public struct Either<TLeft,TRight>
{
private TLeft? _left;
private TRight? _right;
[MemberNotNullWhen(true,nameof(_left)), MemberNotNullWhen(false,nameof(_right))]
public bool IsLeft {get;init;}
public bool IsRight => !IsLeft;
private Either(TLeft? _left, TRight? right, bool isLeft)
{
this._left = _left;
_right = right;
IsLeft = isLeft;
// Union<int,long,double>.Create(5,union =>
// {
// union.Set(5.0);
// var s = union.Match(
// i => i.ToString(),
// i => i.ToString(),
// i => i.ToString()
// );
// });
}
public (Option<TLeft> left, Option<TRight> right) Deconstruct() => (_left,_right);
[MemberNotNullWhen(true,nameof(_right)),MemberNotNullWhen(false,nameof(_left))]
public TLeft Reduce(Func<TRight,TLeft> mapping) => IsLeft?_left:mapping(_right);
public TResult Match<TResult>(Func<TLeft,TResult> left, Func<TRight,TResult> right) => IsLeft ? left(_left) : right(_right);
Either<TNewLeft, TRight> MapLeft<TNewLeft>(Func<TLeft, TNewLeft> mapping) => IsLeft? Either<TNewLeft,TRight>.Left(mapping(_left)) :Either<TNewLeft,TRight>.Right(_right);
Either<TLeft, TNewRight> MapRight<TNewRight>(Func<TRight, TNewRight> mapping) => IsLeft? Either<TLeft,TNewRight>.Left(_left) :Either<TLeft,TNewRight>.Right(mapping(_right));
public static Either<TLeft,TRight> Left(TLeft left) => new(left,default,true);
public static Either<TLeft,TRight> Right(TRight right) => new(default,right,false);
}
public ref struct Union<T,T2,T3> where T : unmanaged where T2 : unmanaged where T3 : unmanaged
{
private byte _type;
private Span<byte> _data;
public static unsafe int SizeInBytes => System.Math.Max(System.Math.Max(sizeof(T),sizeof(T2)),sizeof(T3));
public Union(Span<byte> buffer)
{
_data = buffer;
}
public Union()
{
_data = new byte[SizeInBytes];
}
public static void Create(T value,Action<Union<T,T2,T3>> action)
{
Span<byte> span = stackalloc byte[SizeInBytes];
var union = new Union<T,T2,T3>(span);
union.Set(value);
action(union);
}
public static void Create(T2 value,Action<Union<T,T2,T3>> action)
{
Span<byte> span = stackalloc byte[SizeInBytes];
var union = new Union<T,T2,T3>(span);
union.Set(value);
action(union);
}
public static void Create(T3 value,Action<Union<T,T2,T3>> action)
{
Span<byte> span = stackalloc byte[SizeInBytes];
var union = new Union<T,T2,T3>(span);
union.Set(value);
action(union);
}
public void Set(in T value)
{
System.Runtime.InteropServices.MemoryMarshal.Write(_data, value);
_type = 1;
}
public void Set(in T2 value)
{
System.Runtime.InteropServices.MemoryMarshal.Write(_data, value);
_type = 2;
}
public void Set(in T3 value)
{
System.Runtime.InteropServices.MemoryMarshal.Write(_data, value);
_type = 3;
}
public void Match(
Action<T> t,
Action<T2> t2,
Action<T3> t3
)
{
switch(_type)
{
case 1:
t(As<T>());
break;
case 2:
t2(As<T2>());
break;
case 3:
t3(As<T3>());
break;
};
}
public TResult Match<TResult>(
Func<T,TResult> t,
Func<T2,TResult> t2,
Func<T3,TResult> t3
) => _type switch
{
1=>t(As<T>()),
2=>t2(As<T2>()),
3=>t3(As<T3>()),
_ => throw new NotSupportedException()
};
public ref T As<T>()
where T : unmanaged
{
return ref System.Runtime.InteropServices.MemoryMarshal.Cast<byte, T>(_data)[0];
}
}

View File

@@ -1,51 +1,51 @@
using System.Diagnostics.CodeAnalysis; // using System.Diagnostics.CodeAnalysis;
namespace SJK.Functional; // namespace SJK.Functional;
public interface IOption<T> : IEquatable<IOption<T>> // public interface IOption<T> : IEquatable<IOption<T>>
{ // {
/// <summary> // /// <summary>
/// Applies a function to the contained value if it exists (is not None), otherwise applies a default function. // /// Applies a function to the contained value if it exists (is not None), otherwise applies a default function.
/// </summary> // /// </summary>
/// <param name="onSome">Function to apply if the option contains a value.</param> // /// <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> // /// <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> // /// <returns>The result of applying either the onSome or onNone function.</returns>
TResult Match<TResult>(Func<T, TResult> onSome, Func<TResult> onNone); // TResult Match<TResult>(Func<T, TResult> onSome, Func<TResult> onNone);
void Match(Action<T> onSome,Action onNone); // void Match(Action<T> onSome,Action onNone);
/// <summary> // /// <summary>
/// Chains operations on the contained value using a function that returns an option. // /// Chains operations on the contained value using a function that returns an option.
/// </summary> // /// </summary>
/// <param name="f">A function that takes the contained value and returns an option.</param> // /// <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> // /// <returns>An option resulting from applying the function f to the contained value.</returns>
IOption<TResult> Bind<TResult>(Func<T, IOption<TResult>> f); // IOption<TResult> Bind<TResult>(Func<T, IOption<TResult>> f);
/// <summary> // /// <summary>
/// Maps a function over the contained value if it exists (is not None). // /// Maps a function over the contained value if it exists (is not None).
/// </summary> // /// </summary>
/// <param name="f">The function to apply to the contained value.</param> // /// <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> // /// <returns>An option containing the result of applying f to the contained value.</returns>
IOption<TResult> Map<TResult>(Func<T, TResult> f); // IOption<TResult> Map<TResult>(Func<T, TResult> f);
/// <summary> // /// <summary>
/// Returns the contained value if it exists (is not None), otherwise returns the provided default value. // /// Returns the contained value if it exists (is not None), otherwise returns the provided default value.
/// </summary> // /// </summary>
/// <param name="aDefault">The default value to return if the option does not contain a value.</param> // /// <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> // /// <returns>The contained value or the default value.</returns>
T Or(T aDefault); // T Or(T aDefault);
/// <summary> // /// <summary>
/// Returns the contained value if it exists (is not None), otherwise calls the provided default function. // /// Returns the contained value if it exists (is not None), otherwise calls the provided default function.
/// </summary> // /// </summary>
/// <param name="aDefault">The default value to return if the option does not contain a value.</param> // /// <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> // /// <returns>The contained value or the default value.</returns>
T Or(Func<T> aDefault); // T Or(Func<T> aDefault);
/// <summary> // /// <summary>
/// Checks if the option contains a value (is not None) and outputs it if true. // /// Checks if the option contains a value (is not None) and outputs it if true.
/// </summary> // /// </summary>
/// <param name="value">An out parameter that will be assigned the contained value if it exists.</param> // /// <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> // /// <returns>true if the option contains a value; false otherwise.</returns>
bool HasValue([NotNullWhen(true)]out T? value); // bool HasValue([NotNullWhen(true)]out T? value);
// [Obsolete] // // [Obsolete]
bool HasValue(); // bool HasValue();
} // }

View File

@@ -1,42 +1,42 @@
namespace SJK.Functional; // namespace SJK.Functional;
public sealed class Left<TLeft, TRight> : IEither<TLeft, TRight> // public sealed class Left<TLeft, TRight> : IEither<TLeft, TRight>
{ // {
private readonly TLeft _value; // private readonly TLeft _value;
public Left(TLeft value){ // public Left(TLeft value){
this._value = value; // this._value = value;
} // }
public IEither<TLeft, T2> Bind<T2>(Func<TRight, IEither<TLeft, T2>> value) // public IEither<TLeft, T2> Bind<T2>(Func<TRight, IEither<TLeft, T2>> value)
{ // {
return new Left<TLeft,T2>(_value); // return new Left<TLeft,T2>(_value);
} // }
public (TLeft?, TRight?) Deconstruct()=>(_value,default(TRight)); // public (TLeft?, TRight?) Deconstruct()=>(_value,default(TRight));
public bool IsRight() => true; // public bool IsRight() => true;
public IEither<TNewLeft, TRight> MapLeft<TNewLeft>(Func<TLeft, TNewLeft> mapping) // public IEither<TNewLeft, TRight> MapLeft<TNewLeft>(Func<TLeft, TNewLeft> mapping)
=> new Left<TNewLeft,TRight>(mapping(this._value)); // => new Left<TNewLeft,TRight>(mapping(this._value));
public IEither<TLeft, TNewRight> MapRight<TNewRight>(Func<TRight, TNewRight> mapping) // public IEither<TLeft, TNewRight> MapRight<TNewRight>(Func<TRight, TNewRight> mapping)
=> new Left<TLeft,TNewRight>(this._value); // => new Left<TLeft,TNewRight>(this._value);
public TResult Match<TResult>(Func<TLeft, TResult> left, Func<TRight, TResult> right) // public TResult Match<TResult>(Func<TLeft, TResult> left, Func<TRight, TResult> right)
{ // {
return left(_value); // return left(_value);
} // }
public void Match(Action<TLeft> left, Action<TRight> right) // public void Match(Action<TLeft> left, Action<TRight> right)
{ // {
left(_value); // left(_value);
} // }
public TLeft Reduce(Func<TRight, TLeft> mapping)=> _value; // public TLeft Reduce(Func<TRight, TLeft> mapping)=> _value;
public override string ToString() // public override string ToString()
{ // {
return $"Left<{typeof(TLeft).Name}> with Value {_value}"; // return $"Left<{typeof(TLeft).Name}> with Value {_value}";
} // }
} // }

View File

@@ -1,31 +1,31 @@
using System.Diagnostics.CodeAnalysis; // using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices; // using System.Runtime.CompilerServices;
namespace SJK.Functional; // namespace SJK.Functional;
public sealed class None<T> : IOption<T> // public sealed class None<T> : IOption<T>
{ // {
public static None<T> Of() => new(); // public static None<T> Of() => new();
[MethodImpl(MethodImplOptions.AggressiveInlining)] // [MethodImpl(MethodImplOptions.AggressiveInlining)]
public TResult Match<TResult>(Func<T, TResult> _, Func<TResult> onNone) => // public TResult Match<TResult>(Func<T, TResult> _, Func<TResult> onNone) =>
onNone(); // onNone();
[MethodImpl(MethodImplOptions.AggressiveInlining)] // [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Match(Action<T> onSome, Action onNone) => onNone(); // public void Match(Action<T> onSome, Action onNone) => onNone();
[MethodImpl(MethodImplOptions.AggressiveInlining)] // [MethodImpl(MethodImplOptions.AggressiveInlining)]
public IOption<TResult> Bind<TResult>(Func<T, IOption<TResult>> f) => new None<TResult>(); // public IOption<TResult> Bind<TResult>(Func<T, IOption<TResult>> f) => new None<TResult>();
[MethodImpl(MethodImplOptions.AggressiveInlining)] // [MethodImpl(MethodImplOptions.AggressiveInlining)]
public IOption<TResult> Map<TResult>(Func<T, TResult> f) => new None<TResult>(); // public IOption<TResult> Map<TResult>(Func<T, TResult> f) => new None<TResult>();
[MethodImpl(MethodImplOptions.AggressiveInlining)] // [MethodImpl(MethodImplOptions.AggressiveInlining)]
public T Or(T aDefault) => aDefault; // public T Or(T aDefault) => aDefault;
public T Or(Func<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([NotNullWhen(true)]out T? value) => (value = default) is not null && false;
public bool HasValue() => false; // public bool HasValue() => false;
public override string ToString() // public override string ToString()
{ // {
return nameof(None<T>); // return nameof(None<T>);
} // }
public bool Equals(IOption<T>? other)=> other is None<T>; // public bool Equals(IOption<T>? other)=> other is None<T>;
} // }

67
Functional/Option.cs Normal file
View File

@@ -0,0 +1,67 @@
using System.Diagnostics.CodeAnalysis;
namespace SJK.Functional;
public readonly struct Option<T> : IOption<T>,
IOption<Option<T>, T>//,
// K<Option,T,Option<T>>,
// IEquatable<Option<T>>
{
private readonly T? _value;
private Option(T? value, bool hasValue)
{
_value = value;
HasValue = hasValue;
}
public static Option<T> None => new Option<T>(default!,false);
public T? Value => _value;
[MemberNotNullWhen(true, nameof(HasValue), nameof(_value))]
public bool HasValue {get;init;}
public static Option<T> Some(T value) => new Option<T>(value, true);
// public bool Equals(Option<T> other)
// {
// return other.HasValue == HasValue && EqualityComparer<T>.Default.Equals(_value,other._value);
// }
public TResult Match<TResult>(Func<T, TResult> onSome, Func<TResult> onNone) => HasValue ? onSome(_value) : onNone();
// public TOption Map<TResult, TOption>(Func<T, TResult> f) where TOption : IOption<TOption, TResult> => HasValue ? TOption.Some(f(Value)) : TOption.None;
// public Option<TResult> Map<TResult>(Func<T, TResult> f) => HasValue ? Option<TResult>.Some(f(Value)) : Option<TResult>.None;
public Option<TResult> Map<TResult>(Func<T,TResult> f) => HasValue ? Option<TResult>.Some(f(_value)) : Option<TResult>.None;
public Option<TResult> Bind<TResult>(Func<T,Option<TResult>> f) => HasValue ? f(_value) : Option<TResult>.None;
public static implicit operator Option<T> (T? nullable) => nullable is not null?Some(nullable) : None;
public static implicit operator T? (Option<T> nullable) => nullable.Value;
// public static implicit operator bool(Option<T> option) => option.HasValue;
public static bool operator true(Option<T> value) => value.HasValue;
public static bool operator false(Option<T> value) => !value.HasValue;
public override int GetHashCode()=> HasValue? _value.GetHashCode() : 0;
public override string ToString() => HasValue ? $"Some({_value})" : $"None<{typeof(T).Name}>()";
// public override bool Equals([NotNullWhen(true)] object? obj) => obj is Option<T> option?Equals(option):false;
// public T Or(Func<T> aDefault) => HasValue?_value:aDefault();
// public T OrDefault(T aDefault) => HasValue?_value:aDefault;
// IOption<TResult> IOption<T>.Map<TResult>(Func<T, TResult> f) => Match<IOption<TResult>>(onSome => Some<TResult>.Of(f(onSome)), ()=>None<TResult>.Of);
// public bool TryGetValue(out T value)
// {
// if (HasValue)
// {
// value = Value;
// return true;
// }
// value = default;
// return false;
// }
}

View File

@@ -1,10 +1,11 @@
using System.Diagnostics; using System.Diagnostics;
using System.Numerics;
namespace SJK.Functional; namespace SJK.Functional;
public static class OptionExtensions public static partial class OptionExtensions
{ {
public static IEnumerable<TResult> Match<T, TResult>(this IEnumerable<IOption<T>> values, Func<T, TResult> onSome, Func<TResult> onNone) public static IEnumerable<TResult> Match<T, TResult>(this IEnumerable<Option<T>> values, Func<T, TResult> onSome, Func<TResult> onNone)
{ {
foreach (var item in values) foreach (var item in values)
{ {
@@ -19,24 +20,24 @@ public static class OptionExtensions
// } // }
// return None<T>.Of(); // return None<T>.Of();
// } // }
public static IOption<T> GetValue<Tkey, T>(this IReadOnlyDictionary<Tkey, T> value, Tkey key) where Tkey : notnull public static Option<T> GetValueOrNone<Tkey, T>(this IReadOnlyDictionary<Tkey, T> value, Tkey key) where Tkey : notnull
{ {
if (value.TryGetValue(key, out var v)) if (value.TryGetValue(key, out var v))
{ {
return v.ToOption(); return v.ToOption();
} }
return None<T>.Of(); return Option<T>.None;
} }
public static IOption<T> OrElse<T>(this IOption<T> option, Func<IOption<T>> fallback) // public static Option<T> OrElse<T>(this Option<T> option, Func<Option<T>> fallback)
{ // {
return option.Match( // return option.Match(
some => option, // some => option,
() => fallback() // () => fallback()
); // );
} // }
public static IOption<TResult> BindUsing<TDisposable, TResult>( public static Option<TResult> BindUsing<TDisposable, TResult>(
this IOption<TDisposable> option, this Option<TDisposable> option,
Func<TDisposable, IOption<TResult>> func) Func<TDisposable, Option<TResult>> func)
where TDisposable : IDisposable where TDisposable : IDisposable
{ {
return option.Match( return option.Match(
@@ -44,48 +45,48 @@ public static class OptionExtensions
{ {
using (some) return func(some); using (some) return func(some);
}, },
() => None<TResult>.Of() () => Option<TResult>.None
); );
} }
public static IOption<T> ToOption<T>(this T? value) => value != null ? Some<T>.Of(value) : None<T>.Of(); // public static IOption<T> ToOption<T>(this T? value) => value != null ? Some<T>.Of(value) : None<T>.Of();
[StackTraceHidden] // [StackTraceHidden]
// [MethodImpl(MethodImplOptions.AggressiveInlining)] // [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static T OrThrow<T, TEx>(this IOption<T> option, Func<TEx> exceptionFactory) where TEx : Exception // public static T OrThrow<T, TEx>(this IOption<T> option, Func<TEx> exceptionFactory) where TEx : Exception
{ // {
if (option.HasValue(out var value)) // if (option.HasValue(out var value))
return value; // return value;
throw exceptionFactory(); // 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) // 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)); // 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) where Tvalue : notnull // public static IEither<L, R> ToEither<Tvalue, L, R>(this Tvalue value, Tvalue successValue, Func<R> ok, Func<Tvalue, L> err) where Tvalue : notnull
{ // {
return value.ToEither(e => e.Equals(successValue), ok, 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 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 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 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 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 T Or<T>(this IOption<T> value, Func<T> @default) => value.Or(@default());
public static IEnumerable<T> OnlySomes<T>(this IEnumerable<IOption<T>> options) public static IEnumerable<T> OnlySomes<T>(this IEnumerable<Option<T>> options)
{ {
foreach (var item in options) foreach (var item in options)
{ {
if (item.HasValue(out var item2)) if (item.HasValue)
yield return item2; yield return item.Value;
} }
} }
// public static None<T> ToNone<T>(this T value) => None<T>.Of(); // 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 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(); // public static IOption<T> ToClassOption<T>(this Option<T> option) => option.HasValue ? option.Value.ToOption() : None<T>.Of();
public static IOption<T> FirstOrNone<T>(this IEnumerable<T> options) => options.Any() ? options.First().ToOption() : None<T>.Of(); public static Option<T> FirstOrNone<T>(this IEnumerable<T> options) => options.Any() ? options.First().ToOption() : Option<T>.None;
public static IOption<T> FirstOrNone<T>(this IEnumerable<T> options, Predicate<T> predicate) public static Option<T> FirstOrNone<T>(this IEnumerable<T> options, Predicate<T> predicate)
{ {
foreach (var item in options) foreach (var item in options)
{ {
@@ -94,6 +95,84 @@ public static class OptionExtensions
return item.ToOption(); return item.ToOption();
} }
} }
return None<T>.Of(); return Option<T>.None;
}
public static Option<T> ToOption<T>(this T? value) => value is null ? Option<T>.None : Option<T>.Some(value);
public static Option<T2> TryGetValue<T,T2>(this Option<IDictionary<T,T2>> option, T key) => option.Map(f => f.TryGetValue(key, out var result)?Option.Some(result):Option.None<T2>());
extension<T>(Option<T>) where T : IAdditionOperators<T,T,T>
{
public static Option<T> operator +(Option<T> left, T right) => left.Map(f => f + right);
}
extension<T>(Option<T>) where T : ISubtractionOperators<T,T,T>
{
public static Option<T> operator -(Option<T> left, T right) => left.Map(f => f - right);
}
extension<T>(Option<T>) where T : IMultiplyOperators<T,T,T>
{
public static Option<T> operator *(Option<T> left, T right) => left.Map(f => f *right);
}
extension<T>(Option<T>) where T : IDivisionOperators<T,T,T>
{
public static Option<T> operator /(Option<T> left, T right) => left.Map(f => f / right);
}
extension<T>(Option<T>) where T : IIncrementOperators<T>
{
public static Option<T> operator ++(Option<T> left) => left.Map(f => f++);
}
extension<T>(Option<T>) where T : IDecrementOperators<T>
{
public static Option<T> operator --(Option<T> left) => left.Map(f => f--);
}
extension<T>(Option<T>) where T : IModulusOperators<T,T,T>
{
public static Option<T> operator %(Option<T> left, T right) => left.Map(f => f % right);
}
extension<T>(Option<T> _) where T : IShiftOperators<T,T,T>
{
public static Option<T> operator <<(Option<T> left, T right) => left.Map(f => f << right);
public static Option<T> operator >>(Option<T> left, T right) => left.Map(f => f >> right);
public static Option<T> operator >>>(Option<T> left, T right) => left.Map(f => f >>> right);
}
extension<T>(Option<T>) where T : IBitwiseOperators<T,T,T>
{
public static Option<T> operator &(Option<T> left, T right) => left.Map(f => f & right);
public static Option<T> operator |(Option<T> left, T right) => left.Map(f => f | right);
public static Option<T> operator ^(Option<T> left, T right) => left.Map(f => f ^ right);
public static Option<T> operator ~(Option<T> left) => left.Map(f => ~f);
}
extension<T>(Option<T>) where T : IComparisonOperators<T,T,T>
{
public static Option<T> operator >(Option<T> left, T right) => left.Map(f => f > right);
public static Option<T> operator <(Option<T> left, T right) => left.Map(f => f < right);
public static Option<T> operator >=(Option<T> left, T right) => left.Map(f => f >= right);
public static Option<T> operator <=(Option<T> left, T right) => left.Map(f => f <= right);
}
extension<T>(Option<T>) where T : IUnaryPlusOperators<T,T>
{
public static Option<T> operator +(Option<T> left) => left.Map(f => +f);
}
extension<T>(Option<T>) where T : IUnaryNegationOperators<T,T>
{
public static Option<T> operator -(Option<T> left) => left.Map(f => -f);
}
extension<T>(in Option<T> option) where T : IComparable<T>
{
public int CompareTo(T? value) => option.Map(f => f.CompareTo(value));
}
extension<T>(in Option<T> option) where T : IParsable<T>
{
public static Option<T> TryParse(in string? value, IFormatProvider formatProvider) => T.TryParse(value, formatProvider, out var result)?Option.Some(result):Option.None<T>();
public static Option<T> Parse(in string value, IFormatProvider formatProvider) => T.Parse(value, formatProvider);
}
extension<T>(Option<T>) where T : IEqualityOperators<T,T,bool>
{
public static Option<bool> operator ==(Option<T> left, T right) => left.Map(f => f == right);
public static Option<bool> operator !=(Option<T> left, T right) => left.Map(f => f != right);
} }
} }

View File

@@ -1,40 +1,104 @@
using System.Diagnostics; // using System.Diagnostics;
using System.Diagnostics.CodeAnalysis; // using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices; // using System.Runtime.CompilerServices;
// using SJK.Functional;
namespace SJK.Functional; // namespace SJK.Functional
// {
// /// <summary>
// /// A simple implementation of a monadic option, which can hold either a value of type T or no value.
// /// </summary>
// 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);
public struct Option<T> : IEquatable<Option<T>> // /// <summary>
{ // /// A constructor for creating an instance of the Option struct.
private readonly T? _value; // /// </summary>
[MemberNotNullWhen(true, nameof(_value))] // private Option(T? value, bool hasValue)
public bool HasValue { get; } // {
public static Option<T> None => new(default, false); // Debug.Assert(!(value is null && hasValue), "Can not create an option with a null value had say it has one");
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; // _value = value;
HasValue = hasValue; // HasValue = hasValue;
} // }
public T? Value => HasValue ? _value : throw new InvalidOperationException("Can not retrive value when there is no value.");
// [MethodImpl(MethodImplOptions.AggressiveInlining)] // /// <summary>
public TResult Match<TResult>(Func<T, TResult> some, Func<TResult> none) => HasValue ? some(_value) : none(); // /// Gets the held value if it exists. Throws an exception if there's no value.
// [MethodImpl(MethodImplOptions.AggressiveInlining)] // /// </summary>
public Option<TResult> Map<TResult>(Func<T, TResult> f) => HasValue ? Option<TResult>.Some(f(_value)) : Option<TResult>.None; // public T? Value => HasValue ? _value : throw new InvalidOperationException("Can not retrieve value when there is no value.");
// [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); // /// <summary>
// /// Applies a function to the held value if it exists, otherwise applies another function.
// /// </summary>
// /// <typeparam name="TResult">The type of result produced by the functions.</typeparam>
// public TResult Match<TResult>(Func<T, TResult> some, Func<TResult> none)
// {
// // If we have a value, apply 'some' to it. Otherwise, apply 'none'.
// return HasValue ? some(_value) : none();
// }
public bool Equals(Option<T> other) => (HasValue == other.HasValue) && (!HasValue || EqualityComparer<T>.Default.Equals(_value, other._value)); // /// <summary>
// /// Maps the held value if it exists using the given function, otherwise returns an empty option.
// /// </summary>
// /// <typeparam name="TResult">The type of result produced by the mapping function.</typeparam>
// public Option<TResult> Map<TResult>(Func<T, TResult> f)
// {
// // If we have a value, map it and wrap the result in another option. Otherwise, return an empty option.
// return HasValue ? Option<TResult>.Some(f(_value)) : Option<TResult>.None;
// }
public override int GetHashCode() => HasValue ? EqualityComparer<T>.Default.GetHashCode(_value) : 0; // /// <summary>
public override string ToString() => HasValue ? $"Some({_value})" : $"None<{typeof(T).Name}>()"; // /// Binds the held value if it exists using the given function, otherwise returns an empty option.
} // /// </summary>
// /// <typeparam name="TResult">The type of result produced by the binding function.</typeparam>
// public Option<TResult> Bind<TResult>(Func<T, Option<TResult>> f)
// {
// // If we have a value, bind it and wrap the result in another option. Otherwise, return an empty option.
// return HasValue ? f(_value) : Option<TResult>.None;
// }
// /// <summary>
// /// Returns the held value if it exists, otherwise returns a default value.
// /// </summary>
// public T OrDefault(T value)
// {
// // If we have a value, return it. Otherwise, return the default value.
// return HasValue ? _value : value;
// }
// /// <summary>
// /// Returns the held value if it exists, otherwise returns a result from a factory function.
// /// </summary>
// public T Or(Func<T> factory)
// {
// // If we have a value, return it. Otherwise, invoke the factory function and return its result.
// return HasValue ? _value : factory();
// }
// public override bool Equals([NotNullWhen(true)] object? obj) => obj is Option<T> other && Equals(other);
// /// <summary>
// /// Checks for equality with another option of type T.
// /// </summary>
// public bool Equals(Option<T> other)
// {
// // If both options have values, check their equality. Otherwise, consider them equal if they're both empty.
// return (HasValue == other.HasValue) && (!HasValue || EqualityComparer<T>.Default.Equals(_value, other._value));
// }
// public override int GetHashCode() => HasValue ? EqualityComparer<T>.Default.GetHashCode(_value) : 0;
// /// <summary>
// /// Returns a string representation of this option.
// /// </summary>
// public override string ToString()
// {
// // If we have a value, return it as a 'Some' with the value. Otherwise, return an empty 'None'.
// return HasValue ? $"Some({_value})" : $"None<{typeof(T).Name}>()";
// }
// }
// }

280
Functional/RefOption.cs Normal file
View File

@@ -0,0 +1,280 @@
using System.Diagnostics.CodeAnalysis;
using System.Numerics;
using System.Runtime.CompilerServices;
namespace SJK.Functional;
public interface IOption<out T>
{
T? Value {get;}
[MemberNotNullWhen(true,nameof(Value))]
bool HasValue {get;}
}
// public interface K<in F,A> where F : allows ref struct;
// public interface K<in F,A, TSelf> : K<F,A> where TSelf : K<F,A,TSelf>, allows ref struct where F : allows ref struct;
// public interface Functor<F>
// where F : Functor<F>, allows ref struct
// {
// // public static abstract K<F,B> Map<A, B>(Func<A,B> f, K<F,A> thing);
// public static abstract TFunctor Map<A, B,TFunctor,TSource>(Func<A,B> f, TSource thing) where TFunctor : K<F,B,TFunctor>, allows ref struct where TSource : K<F,A,TSource>, allows ref struct;
// }
// public static partial class OptionExtensions
// {
// static string hello = "world";
// struct testttt
// {
// public int gg;
// }
// public static void tt()
// {
// var gg = new testttt();
// var t = Option.SomeRef(ref gg).Map((ref f) => ref f.gg).Map(f => f.ToString());
// Func<int,string> tostring = f=>f.ToString();
// Option.Map(tostring, t);
// gg.gg = 5;
// var a = Option.Some(5).Map(f => f.ToString()).Map(f => f + f);
// Func<string,bool> tostring = f=>f.Contains('5');
// var res = Option.Map(a,tostring);
// var opt = RefOption<testttt>.Some(ref gg);
// var r = opt.MapRef(f => ref f.gg);
// opt.MapRef()
// var s = tostring.Map(opt);
// if (s.HasValue)
// {
// Console.WriteLine(s.Value);
// }
// Option<int>.Some(5).Match( (int f) => f.ToString(), () => "none");
// Option<int>.None.IfSome((int some) => {});
// Option<int>.None.Map((some) => some.ToString());
// Option<int>.None.Bind((some) => Option<string>.Some(some.ToString()));
// int num = 5;
// string num2 = "gg";
// RefOption<int>.Some(ref num).Match( (int f) => f.ToString(), () => "none");
// RefOption<int>.None.IfSome((int some) => {});
// RefOption<int>.None.Map((some) => some.ToString());
// RefOption<int>.None.Bind((some) => Option<string>.Some(some.ToString()));
// RefOption<int>.None.Map((ref some) => ref hello);
// RefOption<int>.None.Bind((ref some) => RefOption<string>.Some(ref hello));
// Option<string> result = Option.Some(5).Map(f => f.ToString());
// RefOption<string> result2 = RefOption<string>.Some(ref num2);
// // Option<int> res = Option.Map( f => f.Length,result).As();
// int test(string value)=>value.Length;
// Func<string,int> factory = test;
// var a = factory.Map(result);
// var aa = result2.MapRef(factory);
// // IOptionCase<string> classOption = new Some<string>("5");
// // IOptionCase<object> classOption1 = classOption;
// // var result = classOption1 switch
// // {
// // Some<string> some => some.Value,
// // None none => "None",
// // _ => "hello"
// // };
// }
// // extension<TSource,T>(TSource source) where TSource : K<Option,T,TSource>
// // {
// // public static TFunctor As<TFunctor>(TSource self) where TFunctor : => self;
// // }
// public static Option<T> As<T>(this K<Option,T> self) => (Option<T>) self;
// // public static K<F,B> map<F,A,B>(Func<A,B> f, K<F,A> fa) where F : Functor<F> => F.Map(f,fa);
// public static TFunctor map<F,A,B,TFunctor,TSource>(Func<A,B> f, TSource fa) where F : Functor<F>, allows ref struct where TSource : K<F,A,TSource>, allows ref struct where TFunctor : K<F,B,TFunctor>, allows ref struct => F.Map<A,B,TFunctor,TSource>(f,fa);
// public static Option<B> Map<A,B,TSource>(this Func<A,B> f, TSource ma) where TSource : K<Option,A,TSource>, allows ref struct => map<Option,A,B,Option<B>,TSource>(f,ma).As();
// public static Option<B> Map<A,B,TSource>(this TSource ma, Func<A,B> f) where TSource : K<Option,A,TSource>, allows ref struct => map<Option,A,B,Option<B>,TSource>(f,ma).As();
// // public static RefOption<B> MapRef<A,B,TSource>(this TSource ma, RefOption<A>.RefSelector<B> f) where TSource : K<Option,A,TSource>, allows ref struct => map<Option,A,B,RefOption<B>,TSource>(f,ma);
// public static TFunctor Map<A,B,TSource,TFunctor>(this Func<A,B> f, TSource ma) where TSource : K<Option,A,TSource>, allows ref struct where TFunctor : K<Option,B,TFunctor>, allows ref struct => map<Option,A,B,TFunctor,TSource>(f,ma);
// public static TFunctor Map<A,B,TSource,TFunctor>(this TSource ma, Func<A,B> f) where TSource : K<Option,A,TSource>, allows ref struct where TFunctor : K<Option,B,TFunctor>, allows ref struct => map<Option,A,B,TFunctor,TSource>(f,ma);
// // public static TFunctor MapRef<A,B,TSource,TFunctor>(this RefOption<A>.RefSelector<B> f, TSource ma) where TSource : K<Option,A,TSource>, allows ref struct where TFunctor : K<Option,B,TFunctor>, allows ref struct => map<Option,A,B,TFunctor,TSource>(f,ma);
// // extension<A,B>(Func<A,B> f)
// // {
// // // public static TFunctor Map<TSource,TFunctor>( TSource ma) where TSource : K<Option,A,TSource>, allows ref struct where TFunctor : K<Option,B,TFunctor>, allows ref struct => map<Option,A,B,TFunctor,TSource>(f,ma);
// // }
// // public static Option<B> Map<A,B>(this Func<A,B> f, K<Option,A,Option<A>> ma) => map<K<Option,A,Option<A>>,A,B,Option<B>,(f,ma).As();
// public static Option<T> ToOption<T,TOption>(this T? value) where T : class => value is null ? Option<T>.None : Option<T>.Some(value);
// public static Option<T> ToOption<T,TOption>(this T? value) where T : struct => !value.HasValue ? Option<T>.None : Option<T>.Some(value.Value);
// public static void IfSome<T, TOption>(this TOption option, Action<T> action) where TOption : struct, IOption<TOption, T>, allows ref struct //where T : allows ref struct
// {
// if (option.HasValue)
// {
// action(option.Value);
// }
// }
// // public static IOptionCase<T> ToCase<T>(this IOption<T> option) => option.HasValue ? new Some<T>(option.Value) : None<T>.Of;
// // public static TOptionResult Map<TOption,TResult,T,TOptionResult>(this TOption self, Func<T, TResult> f)
// // where TOption : IOption<T>, allows ref struct
// // where TOptionResult : IOption<TOptionResult,TResult>, allows ref struct
// // => self.HasValue ? TOptionResult.Some(f(self.Value)) : TOptionResult.None;
// // public static TOptionResult Bind<TOption,TResult,T,TOptionResult>(this TOption self, Func<T, TOptionResult> f)
// // where TOption : IOption<T>, allows ref struct
// // where TOptionResult : IOption<TOptionResult,TResult>, allows ref struct
// // => self.HasValue ? f(self.Value) : TOptionResult.None;
// public static TResult Match<TSelf, TResult, T>(this TSelf self, Func<T, TResult> onSome, Func<TResult> onNone) where TSelf : IOption<T>, allows ref struct
// => self.HasValue ? onSome(self.Value) : onNone();
// public static void IfNone<T, TOption>(this TOption option, Action action) where TOption : struct, IOption<TOption, T>, allows ref struct //where T : allows ref struct
// {
// if (!option.HasValue)
// {
// action();
// }
// }
// public static TOption GetValueOrNone<TKey,T,TOption>(this IDictionary<TKey,T> dict, TKey key) where TKey : notnull where T : IEquatable<T> where TOption : struct, IOption<TOption,T>, allows ref struct
// {
// if (dict.TryGetValue(key, out var result))
// {
// return TOption.Some(result);
// }
// return TOption.None;
// }
// public static bool TryGetValue<T,TOption>(this TOption option,[NotNullWhen(true)] out T? value) where TOption : struct, IOption<TOption,T>, allows ref struct
// {
// value = option.Value;
// return false;
// }
// // public static TOption BindAs<TOption,T,TSelf>(this TSelf self) where TSelf : IOption<T>, allows ref struct where TOption : IOption<TOption,T> => self.HasValue ? TOption.Some(self.Value) : TOption.None;
// // public static TOption BindAs<TSelf,T,TOption,TResult>(this TSelf option, Func<T,TOption> f)
// // where TSelf : IOption<TSelf,T>
// // where TOption : IOption<TOption,TResult> =>
// // option.HasValue?f(option.Value) : TOption.None;
// public static T? ToNullable<T>(this IOption<T> option) where T : struct
// {
// if (option.HasValue)
// {
// return option.Value;
// }
// return default;
// }
// public static T Or<TSelf,T>(this TSelf option, T @default) where TSelf : struct, IOption<T>, allows ref struct => option.HasValue ? option.Value : @default;
// public static T OrDefault<TSelf,T>(this TSelf option, Func<T> @default) where TSelf : struct, IOption<T> , allows ref struct => option.HasValue ? option.Value : @default();
// }
public interface IOption<TSelf,T> : IOption<T>/*, IEquatable<TSelf>*/ where TSelf : IOption<TSelf,T>//, allows ref struct
{
// void Match(Action<T> onSome,Action onNone);
// IOption<TResult> Bind<TResult>(Func<T, IOption<TResult>> f);
// TSelf Map<TOptionResult,TResult>(Func<T, TResult> f) where TOptionResult : IOption<TOptionResult,TResult> where TResult : allows ref struct;
// T Or(Func<T> aDefault);
// [MemberNotNullWhen(true,nameof(HasValue))]
// T Value {get;}
public static abstract TSelf Some(T value);
public static abstract TSelf None {get;}
// public TOption BindAs<TOption>()where TOption : IOption<TOption,T>, allows ref struct => HasValue ? TOption.Some(Value) : TOption.None;
}
public class Option //: Functor<Option>
{
// public static K<Option, B> Map<A, B>(Func<A, B> f, K<Option, A> thing)
// {
// return thing.As().Map(f);
// }
// public static TFunctor Map<A, B, TFunctor>(Func<A, B> f, K<Option, A> thing) where TFunctor : K<Option, B>
// {
// return thing.As().Map(f);
// }
// public static TFunctor Map<A, B, TFunctor, TSource>(Func<A, B> f, TSource thing)
// where TFunctor : K<Option, B, TFunctor>, allows ref struct
// where TSource : K<Option, A, TSource>, allows ref struct
// {
// return f.Map<A,B,TSource,TFunctor>(thing);
// }
public static Option<T> Some<T>(T value) => Option<T>.Some(value);
public static Option<T> None<T>() => Option<T>.None;
// public static RefOption<T> SomeRef<T>(ref T value) => RefOption<T>.Some(ref value);
// public static RefOption<T> NoneRef<T>() => RefOption<T>.None;
}
// public interface IRefStruct<TSelf,T> where TSelf : IRefStruct<TSelf,T>, allows ref struct
// {
// }
// public readonly ref struct RefOption<T> : IRefStruct<RefOption<T>,T>, IOption<RefOption<T>, T>,K<Option,T,RefOption<T>>// where T : IEquatable<T>//, allows ref struct
// {
// public readonly ref T? Value => ref _value;
// readonly T? IOption<T>.Value => _value;
// private readonly ref T? _value;
// private RefOption(ref T value, bool hasValue) : this()
// {
// _value = value;
// HasValue = hasValue;
// }
// private RefOption(T value, bool hasValue) : this()
// {
// _value = value;
// HasValue = hasValue;
// }
// public RefOption()
// {
// HasValue = false;
// _value = default!;
// }
// [MemberNotNullWhen(true,nameof(Value), nameof(_value), nameof(IOption<T>.Value))]
// public bool HasValue {get; init;}
// public unsafe readonly RefOption<TResult> MapUnsafe<TResult>(delegate*<ref T, ref TResult> f)
// // where TResult : unmanaged, IEquatable<TResult>//, allows ref struct
// =>
// HasValue ? RefOption<TResult>.Some(ref f(ref _value)) : RefOption<TResult>.None;
// public unsafe readonly RefOption<TResult> BindUnsafe<TResult>(delegate*<ref T, RefOption<TResult>> f)
// // where TResult : unmanaged, IEquatable<TResult>//, allows ref struct
// =>
// HasValue ? f(ref _value) : RefOption<TResult>.None;
// public readonly RefOption<TResult> Bind<TResult>(RefBinder<TResult> f ) => HasValue ? f(ref Value) : RefOption<TResult>.None;
// public readonly Option<TResult> Bind<TResult>(Func<T,TResult> f) => HasValue ? Option<TResult>.Some(f(_value)) : Option<TResult>.None;
// public static RefOption<T> Some(ref T value) => new(ref value,false);
// // public static RefOption<T> Some(T value) => new(value,false);
// public static RefOption<T> None => new();
// // public T OrDefault(T aDefault) => HasValue?_value:aDefault;
// // public TResult Match<TResult>(Func<T, TResult> onSome, Func<TResult> onNone)
// // => HasValue ? onSome(_value) : onNone();
// // public T Or(Func<T> aDefault)
// // => HasValue ? _value : aDefault();
// public bool Equals(RefOption<T> other)
// {
// return other.HasValue == HasValue && EqualityComparer<T>.Default.Equals(_value,other._value);
// }
// // public readonly TOption Map<TResult, TOption>(Func<T, TResult> f) where TOption : IOption<TOption, TResult> => HasValue ? TOption.Some(f(_value)) : TOption.None;
// public readonly Option<TResult> Map<TResult>(Func<T, TResult> f) => HasValue ? Option<TResult>.Some(f(Value)) : Option<TResult>.None;
// public readonly RefOption<TResult> Map<TResult>(RefSelector<TResult> f) => HasValue ? RefOption<TResult>.Some(ref f(ref Value)) : RefOption<TResult>.None;
// public TOption BindAs<TOption>() where TOption : IOption<TOption,T> => HasValue ? TOption.Some(Value) : TOption.None;
// static RefOption<T> IOption<RefOption<T>, T>.Some(T value) => new(value,false);
// public delegate RefOption<TResult> RefBinder<TResult>( ref T source);
// public delegate ref TResult RefSelector<TResult>(ref T value);
// /// <summary>
// /// Maps the Option, resulting a not ref struct vesion being boxed and returned
// /// </summary>
// /// <typeparam name="TResult"></typeparam>
// /// <param name="f"></param>
// /// <returns></returns>
// // IOption<TResult> IOption<T>.Map<TResult>(Func<T, TResult> f) => HasValue ? Some<TResult>.Of(f(_value)) : None<TResult>.Of;
// // public bool TryGetValue(out T value)
// // {
// // if (HasValue)
// // {
// // value = Value;
// // return true;
// // }
// // value = default;
// // return false;
// // }
// // public static implicit operator RefStruct<T>(T value) => Some(value);
// }

46
Functional/Result.cs Normal file
View File

@@ -0,0 +1,46 @@
// using System.Diagnostics.CodeAnalysis;
// namespace SJK.Functional;
// public interface IResult
// {
// bool Ok {get;}
// bool Error {get;}
// }
// public interface IResult<TSuccess> : IResult
// {
// }
// public interface IResult<TSuccess,TError> : IResult<TSuccess>;
// public readonly struct Result : IResult
// {
// private readonly bool _isSuccess;
// public readonly bool Ok =>_isSuccess;
// public readonly bool Error =>!_isSuccess;
// }
// public readonly struct Result<TSuccess> : IResult<TSuccess>
// {
// readonly private TSuccess _success;
// private readonly bool _isSuccess;
// [MemberNotNullWhen(true,nameof(_success))]
// public readonly bool Ok =>_isSuccess;
// [MemberNotNullWhen(false,nameof(_success))]
// public readonly bool Error =>!_isSuccess;
// public readonly TResult Match<TResult>(Func<TSuccess,TResult> success, Func<TResult> error)
// => Ok?success(_success):error();
// }
// public readonly struct Result<TSuccess,TError> : IResult<TSuccess,TError>
// {
// private readonly TSuccess? _success;
// private readonly TError? _error;
// private readonly bool _isSuccess;
// [MemberNotNullWhen(true,nameof(_success))]
// [MemberNotNullWhen(false,nameof(_error))]
// public readonly bool Ok =>_isSuccess;
// [MemberNotNullWhen(true,nameof(_error))]
// [MemberNotNullWhen(false,nameof(_success))]
// public readonly bool Error =>!_isSuccess;
// public readonly TResult Match<TResult>(Func<TSuccess,TResult> success, Func<TError,TResult> error)
// => Ok?success(_success):error(_error);
// }

View File

@@ -1,38 +1,38 @@
namespace SJK.Functional; // namespace SJK.Functional;
public sealed class Right<TLeft, TRight> : IEither<TLeft, TRight> // public sealed class Right<TLeft, TRight> : IEither<TLeft, TRight>
{ // {
private readonly TRight _value; // private readonly TRight _value;
public Right(TRight value){ // public Right(TRight value){
this._value = value; // this._value = value;
} // }
public (TLeft?, TRight?) Deconstruct()=>(default(TLeft),_value); // public (TLeft?, TRight?) Deconstruct()=>(default(TLeft),_value);
public IEither<TNewLeft, TRight> MapLeft<TNewLeft>(Func<TLeft, TNewLeft> mapping) // public IEither<TNewLeft, TRight> MapLeft<TNewLeft>(Func<TLeft, TNewLeft> mapping)
=> new Right<TNewLeft,TRight>(this._value); // => new Right<TNewLeft,TRight>(this._value);
public IEither<TLeft, TNewRight> MapRight<TNewRight>(Func<TRight, TNewRight> mapping) // public IEither<TLeft, TNewRight> MapRight<TNewRight>(Func<TRight, TNewRight> mapping)
=> new Right<TLeft,TNewRight>(mapping(this._value)); // => new Right<TLeft,TNewRight>(mapping(this._value));
public TLeft Reduce(Func<TRight, TLeft> mapping)=> mapping(this._value); // public TLeft Reduce(Func<TRight, TLeft> mapping)=> mapping(this._value);
public override string ToString() // public override string ToString()
{ // {
return $"Right<{typeof(TRight).Name}> with Value {_value}"; // return $"Right<{typeof(TRight).Name}> with Value {_value}";
} // }
public TResult Match<TResult>(Func<TLeft, TResult> left, Func<TRight, TResult> right) // public TResult Match<TResult>(Func<TLeft, TResult> left, Func<TRight, TResult> right)
{ // {
return right(_value); // return right(_value);
} // }
public void Match(Action<TLeft> left, Action<TRight> right) // public void Match(Action<TLeft> left, Action<TRight> right)
{ // {
right(_value); // right(_value);
} // }
public IEither<TLeft, T2> Bind< T2>(Func<TRight, IEither<TLeft, T2>> value) // public IEither<TLeft, T2> Bind< T2>(Func<TRight, IEither<TLeft, T2>> value)
{ // {
return value(_value); // return value(_value);
} // }
public bool IsRight() => false; // public bool IsRight() => false;
} // }

View File

@@ -1,44 +1,44 @@
using System.Diagnostics.CodeAnalysis; // using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices; // using System.Runtime.CompilerServices;
namespace SJK.Functional; // namespace SJK.Functional;
public class Some<T> : IOption<T> // public class Some<T> : IOption<T>
{ // {
private readonly T _data; // private readonly T _data;
private Some(T data) // private Some(T data)
{ // {
_data = data; // _data = data;
} // }
public ref readonly T Value => ref _data; // public ref readonly T Value => ref _data;
public static Some<T> Of(T data) => new(data); // public static Some<T> Of(T data) => new(data);
// [MethodImpl(MethodImplOptions.AggressiveInlining)]//TODO see if these inporve perfomce in gernral cases // // [MethodImpl(MethodImplOptions.AggressiveInlining)]//TODO see if these inporve perfomce in gernral cases
public TResult Match<TResult>(Func<T, TResult> onSome, Func<TResult> _) => // public TResult Match<TResult>(Func<T, TResult> onSome, Func<TResult> _) =>
onSome(_data); // onSome(_data);
// [MethodImpl(MethodImplOptions.AggressiveInlining)] // // [MethodImpl(MethodImplOptions.AggressiveInlining)]
public IOption<TResult> Bind<TResult>(Func<T, IOption<TResult>> f) => f(_data); // public IOption<TResult> Bind<TResult>(Func<T, IOption<TResult>> f) => f(_data);
// [MethodImpl(MethodImplOptions.AggressiveInlining)] // // [MethodImpl(MethodImplOptions.AggressiveInlining)]
public IOption<TResult> Map<TResult>(Func<T, TResult> f) => new Some<TResult>(f(_data)); // public IOption<TResult> Map<TResult>(Func<T, TResult> f) => new Some<TResult>(f(_data));
// [MethodImpl(MethodImplOptions.AggressiveInlining)] // // [MethodImpl(MethodImplOptions.AggressiveInlining)]
public T Or(T _) => _data; // public T Or(T _) => _data;
public T Or(Func<T> aDefault) => _data; // public T Or(Func<T> aDefault) => _data;
public bool HasValue([NotNullWhen(true)]out T? value) => (value = _data) is not null; // public bool HasValue([NotNullWhen(true)]out T? value) => (value = _data) is not null;
public bool HasValue() => true; // public bool HasValue() => true;
// [MethodImpl(MethodImplOptions.AggressiveInlining)] // // [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Match(Action<T> onSome, Action onNone) => onSome(_data); // public void Match(Action<T> onSome, Action onNone) => onSome(_data);
public override string ToString() // public override string ToString()
{ // {
return nameof(Some<T>)+": "+ _data; // return nameof(Some<T>)+": "+ _data;
} // }
public bool Equals(IOption<T>? other) // public bool Equals(IOption<T>? other)
{ // {
if (other is Some<T> some){ // if (other is Some<T> some){
return _data!.Equals(some._data); // return _data!.Equals(some._data);
} // }
return false; // return false;
} // }
} // }