Skip to content

Instantly share code, notes, and snippets.

@SuperJMN
Last active August 12, 2020 15:45
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 SuperJMN/6dd09294ce58acf25374ab25732031b6 to your computer and use it in GitHub Desktop.
Save SuperJMN/6dd09294ce58acf25374ab25732031b6 to your computer and use it in GitHub Desktop.
void Main()
{
var result = ReadUser("JMN")
.Map(u => FindProduct(u))
.Map(p => ReadTechnicalDetails(p))
.Map(pd => View(pd))
.Handle(response => ErrorView(response));
Console.WriteLine(result);
}
Either<Error, User> ReadUser(string name)
{
Func<User> succeed = () => new User(name);
return succeed.FailRandomlyWith(() => new Error(nameof(ReadUser)));
}
Product FindProduct(User user)
{
return new Product(user);
}
Either<Error, ProductDetails> ReadTechnicalDetails(Product product)
{
Func<ProductDetails> succeed = () => new ProductDetails(product);
return succeed.FailRandomlyWith(() => new Error(nameof(ReadTechnicalDetails)));
}
HttpResponse View(ProductDetails product)
{
return new HttpResponse($"Success: {product}");
}
HttpResponse ErrorView(Error error)
{
return new HttpResponse("Failed with error: " + error.Message);
}
abstract public class Either<TLeft, TRight>
{
public abstract Either<TLeft, TNewRight> Map<TNewRight>(Func<TRight, TNewRight> map);
public abstract Either<TLeft, TNewRight> Map<TNewRight>(Func<TRight, Either<TLeft, TNewRight>> map);
public abstract TRight Handle(Func<TLeft, TRight> map);
}
static public class Either
{
public static Either<TLeft, TRight> Success<TLeft, TRight>(TRight right)
{
return new Right<TLeft, TRight>(right);
}
public static Either<TLeft, TRight> Fail<TLeft, TRight>(TLeft left)
{
return new Left<TLeft, TRight>(left);
}
}
class Right<TLeft, TRight> : Either<TLeft, TRight>
{
public Right(TRight value)
{
Value = value;
}
public TRight Value { get; }
public override Either<TLeft, TNewRight> Map<TNewRight>(Func<TRight, TNewRight> map)
{
return Either.Success<TLeft, TNewRight>(map(Value));
}
public override Either<TLeft, TNewRight> Map<TNewRight>(Func<TRight, Either<TLeft, TNewRight>> map)
{
return map(Value);
}
public override TRight Handle(Func<TLeft, TRight> map)
{
return Value;
}
}
class Error
{
public Error(string message)
{
Message = message;
}
public string Message { get; }
}
class Left<TLeft, TRight> : Either<TLeft, TRight>
{
public Left(TLeft value)
{
Value = value;
}
public TLeft Value { get; }
public override Either<TLeft, TNewRight> Map<TNewRight>(Func<TRight, TNewRight> map)
{
return Either.Fail<TLeft, TNewRight>(Value);
}
public override Either<TLeft, TNewRight> Map<TNewRight>(Func<TRight, Either<TLeft, TNewRight>> map)
{
return new Left<TLeft, TNewRight>(Value);
}
public override TRight Handle(Func<TLeft, TRight> map)
{
return map(Value);
}
}
class HttpResponse
{
public HttpResponse(string content)
{
Content = content;
}
public string Content { get; }
}
class User
{
public string Name { get; }
public User(string name)
{
Name = name;
}
public override string ToString()
{
return Name;
}
}
class Product
{
public User User { get; }
public Product(User user)
{
User = user;
}
public override string ToString()
{
return $"Product for {User}";
}
}
class ProductDetails
{
public Product Product { get; }
public ProductDetails(Product product)
{
Product = product;
}
public override string ToString()
{
return $"Product Details for {Product}";
}
}
public static class EitherExtensions
{
private static readonly Random Random = new Random();
public static Either<TLeft, TRight> FailRandomlyWith<TLeft, TRight>(this Func<TRight> succeed, Func<TLeft> fail)
{
if (Random.Next(4) == 0)
{
return Either.Fail<TLeft, TRight>(fail());
}
return Either.Success<TLeft, TRight>(succeed());
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment