0

I'm using C# LanguageExt https://github.com/louthy/language-ext

I have a class MyDto parsed from some Json. The parsing functions returns Either<Error, Mydto>. If the dto matches a given rule, or it is an error, then I would like to get back the result, otherwise, nothing.

The final result should then be of type Option<Either<Error, Mydto>>.

I ended up having something like this

Option<Either<Error, MyDto>> finalResult =  
     MyDto.From("some json") // Returns Either<Error, MyDto>
          .Right(dto => (dto.Equals("something")
             ? Some<Either<Error, IDhResponse>>(Right(dto))
             : None))
          .Left(error => Some<Either<Error, IDhResponse>>(Left(error)));

I don't really like it, as it presents too much repetition.

I then tried this

MyDto.From("some json") // Returns Either<Error, MyDto>
   .Map(dto => dto.Equals("something")
      ? Some(dto)
      : None)

but it returns Either<Error, Option<MyDto>> that looks not so bad if at this point i would be able to bring Option out. Unfortunately I was not able to find anything to that does it.

Does something exist? Or there exist some better way to do what's in my purpose?

maybe something like

 MyDto.From("some json") // Returns Either<Error, MyDto>
   .Where(dto => dto.Equals("something")) // Only applies to Right branch and wrap everything in  Option when fails

Thank you for any advice on this.

Luca Piccinelli
  • 379
  • 1
  • 17

1 Answers1

2

Ok, here are three code solutions:

Either<Exception, int> resultOfParsing = Right(10); // Left(new Exception("error"))

// version 1: make use of "bottom" state:
Either<Exception, int> filterResultUsingBottom = resultOfParsing.Filter(i => i > 5);

var textResultUsingBottom = filterResultUsingBottom.Match(i => $"success: {i}", exception => $"error: {exception.Message}", () => "condition: false");

// version 2: inner option
Either<Exception, Option<int>> filterResultInnerOption = resultOfParsing
    .Map(i => Some(i))
    .FilterT(i => i > 5);

var textResultInnerOption = filterResultInnerOption.Match(noError =>
        noError.Match(i => $"success: {i}", () => "condition: false"),
    exception => $"error: {exception.Message}");

// version 3: outer option
Option<Either<Exception, int>> filterResultOuterOption = filterResultInnerOption.Sequence();

var textResultOuterOption = filterResultOuterOption.Match(noConditionFail =>
        noConditionFail.Match(i => $"success: {i}", exception => $"error: {exception.Message}"),
    () => "condition: false");

As you can see all versions can be used in similar ways (lines with Match). You should select the version you need depending on the type you want to have / pass on in your program.

If you don't care a lot about the difference between "condition failed" and "exception" then version 1 (bottom) might be ok (avoiding type nesting). But I personally prefer the latter solutions. You can switch between them using .Sequence() on demand.

stb
  • 772
  • 5
  • 15