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