Search code examples
c#functional-programminglanguage-ext

How do I bind a method that returns an `Either` to a method that accepts an `Option` in Language-Ext?


For simplicity, I'm presenting a use-case that isn't really realistic (eg role-checking could be done differently, etc), but I'm trying not to confuse the question, so please bear with me.

Suppose I want to write a method that accepts an int, and needs to...

  1. Check the authed used is in the appropriate role to make the request
  2. Check the Id corresponds to a customer in the database
  3. Check if the customer is active

If we get through all that lot, we return the customer, if not we return an error message.

If I use an Either-returning method for step 2, I can do something like this...

static Either<string, int> CheckUser(int n) {
  // Check the authed user is in the right role, etc
  // For simplicity, we'll decide based on the Id
  if (n < 0) {
    return "Not authorised to access customer data";
  }
  return n;
}

static Either<string, Customer> Exists(int n) =>
  // This would check the database
  n < 10 ? "Unknown customer" : new Customer(n, "Jim Spriggs");

static Either<string, Customer> IsActive(Customer c) {
  // This would check the customer, we just use a simple check on the Id for simplicity
  if (c.Id % 2 == 0) {
    return "Inactive";
  }
  return c;
}

record Customer(int Id, string Name);

I can then bind this together as follows...

CheckUser(36)
  .Bind(Exists)
  .Bind(IsActive)
  .Match(n => Console.WriteLine($"Success: {n}"), ex => Console.WriteLine($"Ex: {ex}"));

This works, but I can't help but feel that the Exists method should return an Option<Customer> rather than an Either<string, Customer>, eg (again simplified for clarity)...

static Option<Customer> Exists(int n) =>
    n < 10 ? Option<Customer>.None : new Customer(n, "Jim Spriggs");

However, I'm struggling to work out how to bind this between the other two methods. I thought that I could use Map to convert, but couldn't work out how to do this.

Anyone able to advise? Is it OK to use Either, or should I be using Option? If the latter, how do I fix my code?

Thanks


Solution

  • Use ToEither:

    [Fact]
    public void Answer()
    {
        var actual = CheckUser(36)
            .Bind(i => Exists(i).ToEither("Inactive"))
            .Bind(IsActive)
            .Match(n => $"Success: {n}", ex => $"Ex: {ex}");
        Assert.Equal("Ex: Inactive", actual);
    }
    

    The above test passes.