using System; using System.Collections.Generic; using System.Text; namespace Tools.Maybes { static class test { public static void maybe() { var result = Maybe.Some(false); if(result) { bool value = result; } else { } result.Match(Some: value => { return 10; }, None: () => { return 0; }); var valresult = ValueMaybe.Some(10.1f); if(valresult) { float res = valresult; } else { } valresult.Match(Some: value => { return value * 2; }, None: () => { return 0; }); } /* public void tresult() { var result = Result.Ok("hi"); }*/ } public static class ValueMaybe { public static ValueMaybe Some(T value) => new ValueMaybe(value, true); public static ValueMaybe None() => new ValueMaybe(default, false); } public readonly struct ValueMaybe { private readonly T value; private readonly bool hasValue; public bool Equals(ValueMaybe other) { return other.hasValue == this.hasValue && (ReferenceEquals(value, other.value) || (value?.Equals(other.value) ?? false)); } public override int GetHashCode() { return hasValue ? Math.Abs(value?.GetHashCode() ?? 0) : -1; } public override bool Equals(object obj) { return (obj is ValueMaybe some && Equals(some)) || (hasValue && obj is T val && (ReferenceEquals(val, value) || (value?.Equals(val) ?? false))); } internal ValueMaybe(T value, bool hasValue) { this.hasValue = hasValue; this.value = value; } public static bool operator true(ValueMaybe some) => some.hasValue; public static bool operator false(ValueMaybe some) => !some.hasValue; public static implicit operator T(ValueMaybe input) => input.hasValue ? input.value : throw new InvalidCastException("No value"); public static implicit operator ValueMaybe(T input) => ValueMaybe.Some(input); public T Value => value; public bool HasValue => hasValue; public bool TryGetValue(out T value) { if(HasValue) { value = Value; return true; } value = default; return false; } public void Match(Action Some=null, Action None=null) { if (hasValue) Some?.Invoke(value); else None?.Invoke(); } public V Match(Func Some=null, Func None=null) { if(hasValue) { if (Some != null) return Some(value); else return default; } else { if (None != null) return None(); else return default; } } public static bool operator ==(ValueMaybe left, ValueMaybe right) { return left.Equals(right); } public static bool operator !=(ValueMaybe left, ValueMaybe right) { return !(left == right); } } public sealed class Some : Maybe { public override T Value { get; } internal Some(T value) { Value = value; } public override bool Equals(object obj) { return obj is Some some && (ReferenceEquals(some.Value, Value) || (some.Value?.Equals(Value) ?? false)); } public override int GetHashCode() { return Math.Abs(Value?.GetHashCode() ?? 0); } public override string ToString() { return "Some(" + (Value?.ToString() ?? "null") + ")"; } } public sealed class None : Maybe { internal None() { } public override bool Equals(object obj) { return obj is None; } public override int GetHashCode() { return -1; } public override string ToString() { return "None"; } } public static class Maybe { public static Maybe Some(T value) => new Some(value); public static Maybe None() => new None(); } public abstract class Maybe { public static bool operator true(Maybe input) => input is Some; public static bool operator false(Maybe input) => input is None; public override bool Equals(object obj) { throw new NotImplementedException(); } public override int GetHashCode() { throw new NotImplementedException(); } public override string ToString() { throw new NotImplementedException(); } public static bool operator ==(Maybe left, T right) => left.HasValue && (left == Maybe.Some(right)); public static bool operator !=(Maybe left, T right) => !(left == right); public static bool operator ==(Maybe left, Maybe right) { return ReferenceEquals(left, right) || (left?.Equals(right) ?? false); } public static bool operator !=(Maybe left, Maybe right) => !(left == right); public static implicit operator T(Maybe some) => some is Some thing ? thing : throw new InvalidCastException("No value"); public static implicit operator Maybe(T some) => new Some(some); public virtual T Value => (T)this; public bool HasValue => this is Some; public bool TryGetValue(out T value) { if(this is Some thing) { value = thing.Value; return true; } value = default; return false; } public void Match(Action Some = null, Action None = null) { if (this is Some some) { Some?.Invoke(some.Value); } else if (this is None none) None?.Invoke(); throw new InvalidOperationException("Maybe is neither some nor none."); } public V Match(Func Some = null, Func None = null) { if (this is Some some) { if (Some == null) return default; else return Some(some.Value); } else if (this is None none) { if (None == null) return default; else return None(); } throw new InvalidOperationException("Maybe is neither some nor none."); } } #if REWORK && false public class Ok : Result { public override T Value { get; } public Ok(T value) { Value = value; } } public class Err : Result { public override E Error { get; } public Err(E exception) { Error = exception; } } public static class Result { public static Ok Ok(T value) => new Ok(value); public static Err Err(E value) => new Err(value); } public abstract class Result { public static bool operator true(Result input) => input is Ok; public static bool operator false(Result input) => input is Err; public virtual T Value => (T)this; public virtual E Error => (E)this; public bool TryGetValue(out T value) { if (this is Ok thing) { value = thing.Value; return true; } value = default; return false; } public bool TryGetError(out E value) { if (this is Err thing) { value = thing.Error; return true; } value = default; return false; } public static implicit operator T(Result validResult) => validResult is Ok ok ? ok.Value : throw new InvalidCastException("No value"); public static implicit operator E(Result invalidResult) => invalidResult is Err ok ? ok.Error : throw new InvalidCastException("No exception"); } #endif }