I want to process a set of IEnumerable<Either<Error, TA>> originalListOfEithers such that I can keep/extract data from the type TA objects if they are not in the error (left) state but still maintain the errors for processing later (i.e. log which TA have errors) and end up with a transformed IEnumerable<Either<Error,TB>> transformedListOfEithers.
record TA(IEnumerable<T> ListOfTB, int Prop1, string Prop2)
{
Option<TB> Find(predicate)
}
record TB(Prop3, Prop4)
IEnumerable<Either<Error, TA>> originalListOfEithers;
I then want a resultant list:
IEnumerable<Either<Error, TC>> transformedListOfEithers
Is it possible to get a transformedListOfEithers that is still the same length as the originalListOfEithers such that: if the Find() returns the None option then the TA type is transformed to the Error type else if the Find() returns Some I can transform the TA to TC.
I have tried to use the BindT transformer like so:
var foundTs = ta.BindT(a => a.ListOfT.Find(predicate).ToEither(Error.New($"Couldn't find T for {a.Prop2}"))
But then I lose the scope to the corresponding ta
I have tried this below but the nested Either is causing issues (compile time error) as the values are now not in the same monad (as per How do I bind a Task<List<Card>> to Either<> with Language-Ext)
var transformedListOfEithers = from ta in originalListOfEithers
let tb in ta.ListOfT.Find(predicate).ToEither(Error.New("T could not be found for predicate"))
from b in tb
select new TC(ta.Prop1, b.Prop3)
EDIT: I don not want a .Sequence() call as I want to keep an error per item in the list that could not be processed
It's not clear to me what you want exactly, but BindT
seems to fit.
Maybe this example helps:
var maybeInputs = Prelude.Seq<Either<Error, string>>(/* add items if you want */);
Seq<Either<Error, int>> maybeOutputs = maybeInputs.Map(maybeInput => from input in maybeInput
from output in Prelude.parseInt(input).ToEither(() => Error.New("not an int"))
select output);
Seq<Either<Error, (string input, int output)>> maybeInputOutputTuples = maybeInputs.Map(maybeInput => from input in maybeInput
from output in Prelude.parseInt(input).ToEither(() => Error.New("not an int"))
select (input, output));
// alternative syntax 1
Seq<Either<Error, int>> maybeOutputs = from maybeInput in maybeInputs
select from input in maybeInput
from output in Prelude.parseInt(input).ToEither(() => Error.New("not an int"))
select output;
// alternative syntax 2
Seq<Either<Error, int>> maybeOutputs = maybeInputs.BindT(input => Prelude.parseInt(input).ToEither(() => Error.New("not an int")));