Skip to content

Instantly share code, notes, and snippets.

@dcuccia
Last active September 13, 2020 01:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dcuccia/4029f1cddd7914dc1ae676d8c4af7866 to your computer and use it in GitHub Desktop.
Save dcuccia/4029f1cddd7914dc1ae676d8c4af7866 to your computer and use it in GitHub Desktop.
namespace DiscriminatedUnions
{
using System.Collections.Generic;
using CartState = Union3<CartStateEmpty, CartStateActive, CartStatePaid>;
public class Union3<A, B, C>
{
public Union3(A item) { Item = item; }
public Union3(B item) { Item = item; }
public Union3(C item) { Item = item; }
public dynamic Item { get; }
}
static class Program
{
static void Main(string[] args)
{
const decimal paidAmount = 12.34m;
// no real need for discriminated unions if process is deterministic
// just use the API to guard against unallowed transitions
var paid = new CartStateEmpty()
.AddProduct(Product.ProductX)
.AddProduct(Product.ProductY)
.Pay(paidAmount);
// but discriminated unions quite useful if there's branching
var empty = new CartState(new CartStateEmpty());
var maybeAdded = empty.MaybeAddProduct(Product.ProductX);
var maybeAdded2 = maybeAdded.MaybeAddProduct(Product.ProductY);
var maybePaid = maybeAdded2.MaybePay(paidAmount);
}
public static CartState MaybeAddProduct(this CartState cartState, Product product) => cartState.Item switch
{
CartStateEmpty => product.InStock ? new CartState( new CartStateActive(product) ) : cartState,
CartStateActive csa => new CartState(csa.AddProduct(product)),
_ => cartState
};
public static CartState MaybePay(this CartState cartState, decimal amount) => cartState.Item switch
{
CartStateActive csa => amount <= 1000 ? new CartState(csa.Pay(amount)) : cartState,
_ => cartState
};
}
public class Product
{
public static Product ProductX { get; } = new Product();
public static Product ProductY { get; } = new Product();
public bool InStock { get; }
}
class CartStateEmpty
{
public CartStateActive AddProduct(Product product) => new CartStateActive(product);
}
class CartStateActive
{
private IList<Product> _products;
public CartStateActive(Product product)
{
_products = new List<Product>{ product };
}
public CartStateActive AddProduct(Product product)
{
_products.Add(product);
return this;
}
public CartStatePaid Pay(decimal amount) => new CartStatePaid();
}
class CartStatePaid { }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment