Refactored Option<T> to have opertator lifting and removed ref struct for now.
All checks were successful
Build NuGet / build (push) Successful in 1m43s
All checks were successful
Build NuGet / build (push) Successful in 1m43s
This commit is contained in:
188
.vscode/settings.json
vendored
188
.vscode/settings.json
vendored
@@ -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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -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;
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -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];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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();
|
||||||
}
|
// }
|
||||||
|
|||||||
@@ -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}";
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|||||||
@@ -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
67
Functional/Option.cs
Normal 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;
|
||||||
|
// }
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
280
Functional/RefOption.cs
Normal 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
46
Functional/Result.cs
Normal 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);
|
||||||
|
|
||||||
|
// }
|
||||||
@@ -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;
|
||||||
}
|
// }
|
||||||
@@ -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;
|
||||||
}
|
// }
|
||||||
|
|
||||||
}
|
// }
|
||||||
|
|||||||
Reference in New Issue
Block a user