Search code examples
c#functional-programminglanguage-ext

How do I convert an Either<T1, Card> to Either<T2, Card> with LanguageExt?


I have a method like this...

public static async Task<Either<string, Card>> GetCard(/* parameters */) =>
  // code ommitted for clarity

...which I use like this (all parameters omitted for clarity)...

public static async Task<string> ActivateCard() =>
    await (
        from _ in CheckIssuerHash().ToAsync()
        from card in GetCard().ToAsync()
        from exp in CheckCardDetails().ToAsync()
        from displayNumber in SaveActivation().ToAsync()
        select displayNumber
      )
      .Match(JsonOk, JsonError);

The two methods JasonOk and JsonError are just convenience methods that convert a string into JSON. That all works fine, mainly bcause each of the methods in the Linq query return a Task<Either<string, T>> (where T varies between the methods).

I want to use GetCard in a query with a different generic type...

public static async Task<TransactionRequestStates> ProcessTransaction() =>
    await (
        from _ in CheckTransactionHash().ToAsync()
        from card in GetCard().ToAsync()
        // other methods get called here...
        select TransactionRequestStates.Success
      );

In this case, all other methods in the query return a Task<Either<TransactionRequestStates, T>>, where TransactionRequestStates is an enum. Unlike the ActivateCard method, which is called by a 3rd party, and so needs to return JSON, this method will be used internally, and so can return an enum value.

As it is, I get a compiler error "Cannot implicitly convert type 'LanguageExt.EitherAsync<string, Card>' to 'LanguageExt.Guard".

I think my problem is that I need to work out how to convert the Task<Either<string, T>> that GetCard returns to the Task<Either<TransactionRequestStates, string>> that all the other methods return.

In a nutshell, I want to know if there is way to convert a Task<Either<T1, TRes>> to a Task<Either<T2, TRes>>. That sounds like a standard thing to do in functional programming.

I have a simple mapping from the strings returned by GetCard to the appropriate TransactionRequestStates values, so that's not an issue. I just can't work out where to use this mapping.

I can't help feeling that this is so obvious that I should be able to do it with a single method from LanguageExt, but I'm not clear enough on it to know what.

Anyone able to advise? Please let me know if you need any more code or explanation. Thanks


Solution

  • In a nutshell, I want to know if there is way to convert a Task<Either<T1, TRes>> to a Task<Either<T2, TRes>>. That sounds like a standard thing to do in functional programming.

    You can call either.MapLeft(l => ...) to map the left-type of an Either. So, for Task<Either<T1, TRes>> to a Task<Either<T2, TRes>>, you can call:

    tmx.Bind(mx => mx.MapLeft(l => ...))
    

    Btw, I'm not sure why you've made the call into a Task<Either<L, R>>, none of your code is asynchronous. So, you can remove all of the async/Task stuff from your example.