Skip to content

Instantly share code, notes, and snippets.

@fabiomarreco
Last active January 26, 2018 11:40
Show Gist options
  • Save fabiomarreco/30b355cfd5e9216c9247d1429c3add3b to your computer and use it in GitHub Desktop.
Save fabiomarreco/30b355cfd5e9216c9247d1429c3add3b to your computer and use it in GitHub Desktop.
Maybe implementation in C#
using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
using ProtoBuf;
using System.Diagnostics;
namespace Marreco.Util
{
[DataContract, ProtoContract, JsonConverter(typeof(MaybeJsonConverter))]
[DebuggerNonUserCode]
public struct Maybe<T> : IEquatable<T>, IEquatable<Maybe<T>>
{
[DataMember, ProtoMember(1)]
public readonly bool HasValue;
[DataMember, ProtoMember(2)]
[JsonProperty(ReferenceLoopHandling = ReferenceLoopHandling.Serialize)]
private readonly T _value;
static Maybe()
{
var type = typeof (T);
if (type.IsGenericTypeDefinition && (type.GetGenericTypeDefinition() == typeof(Maybe<>)))
throw new TypeLoadException("Cannot have Maybe<Maybe<>>");
}
public Maybe(T value)
{
_value = value;
HasValue = IsValidValue(value);
}
public static Maybe<T> None { get; } = default(Maybe<T>);
private static bool IsValidValue(T value)
{
if (value == null)
return false;
if (typeof (T) == typeof (string))
return !string.IsNullOrEmpty(value.ToString());
return true;
}
public T ValueOrDefault(T defaultValue = default(T))
{
if (HasValue)
return _value;
else
return defaultValue;
}
public Maybe<TResult> Select<TResult>(Func<T, TResult> f) => this.Select(x => (Maybe<TResult>) f(x));
public void Do(Action<T> f)
{
if (HasValue)
f(_value);
}
public Maybe<TResult> Select<TResult>(Func<T, Maybe<TResult>> f) //monad bind
{
if (HasValue)
return f(_value);
else
return default(Maybe<TResult>);
}
public Maybe<T> Where(Func<T, bool> f)
{
if (HasValue && f(_value))
return this;
else
return default(Maybe<T>);
}
public bool Equals(T other)
{
if (!HasValue)
return !IsValidValue(other);
return _value.Equals(other);
}
public bool Equals(Maybe<T> other)
{
if (!HasValue)
return !other.HasValue;
if (!other.HasValue)
return false;
if ((_value == null) || (other._value == null))
return false;
return _value.Equals(other._value);
}
public override bool Equals(object obj)
{
if (obj is Maybe<T>)
return this.Equals((Maybe<T>) obj);
if (obj is T)
return this.Equals((T) obj);
if (obj == null)
return !this.HasValue;
if (_value != null)
return _value.Equals(obj);
return false;
}
public override int GetHashCode()
{
return (!HasValue) ? 0 : _value.GetHashCode() + 1;
}
public static implicit operator Maybe<T>(T value) => new Maybe<T>(value);
public static bool operator ==(Maybe<T> x, Maybe<T> y) => x.Equals(y);
public static bool operator !=(Maybe<T> x, Maybe<T> y) => !(x == y);
public static bool operator ==(Maybe<T> x, T y) => x.Equals(y);
public static bool operator !=(Maybe<T> x, T y) => !(x == y);
public override string ToString() => HasValue ? $"Some({_value.ToString()})" : "None" ;
public Maybe<TResult> Cast<TResult>()
where TResult : class
{
return this.Select(s => s as TResult);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment