Last active
August 12, 2020 15:45
-
-
Save SuperJMN/6dd09294ce58acf25374ab25732031b6 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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