using System.Threading.Tasks;
public static void Main()
.Bind(orderId => GetOrder(orderId))
.Bind(order => GetClient(order.ClientId));
Console.WriteLine(client);
var none = (-1).ToMaybe()
.Bind(orderId => GetOrder(orderId))
.Bind(order => GetClient(order.ClientId));
var result = Task.Run(async () => {
var asyncClient = await (await 2.ToMaybe()
.Bind(orderId => GetOrderAsync(orderId)))
.Bind(order => GetClientAsync(order.ClientId));
Console.WriteLine(result);
public class Order { public int Id; public int ClientId; public override string ToString() => $"Order{Id}"; }
public class Client { public int Id; public override string ToString() => $"Client{Id}"; }
private static Maybe<Order> GetOrder(int id) => id == -1 ? Maybe<Order>.None : new Order {Id = id, ClientId = id}.ToMaybe();
private static Maybe<Client> GetClient(int id) => id == -1 ? Maybe<Client>.None : new Client {Id = id}.ToMaybe();
private static Task<Maybe<Order>> GetOrderAsync(int id) => Task.FromResult(GetOrder(id));
private static Task<Maybe<Client>> GetClientAsync(int id) => Task.FromResult(GetClient(id));
private readonly T value;
private Maybe(bool hasValue, T value) : this(hasValue) => this.value = value;
private Maybe(bool hasValue) => HasValue = hasValue;
public bool HasValue { get; }
public T Value => HasValue ? value : throw new InvalidOperationException();
public static Maybe<T> None { get; } = new Maybe<T>(false);
public static Maybe<T> Some(T value) => new Maybe<T>(true, value);
public Maybe<U> Bind<U>(Func<T, Maybe<U>> f) => HasValue ? f(value) : Maybe<U>.None;
public async Task<Maybe<U>> Bind<U>(Func<T, Task<Maybe<U>>> f) => HasValue ? await f(value) : Maybe<U>.None;
public override string ToString() => HasValue ? Value.ToString() : "None";
public static class TExtensions
public static Maybe<T> ToMaybe<T>(this T value) => Maybe<T>.Some(value);