如何用LINQ查询语法结合Language-ext BindT单子转换器处理Either序列
问题描述
需要处理IEnumerable<Either<Error, TA>>类型的originalListOfEithers,要求如下:
- 保留原列表长度,每个元素最终转为
Either<Error, TC>类型 - 若原元素是
Left<Error>(错误状态),直接保留该错误 - 若原元素是
Right<TA>(非错误状态):- 调用TA的
Find()方法,若返回None,则转为带对应错误信息的Left<Error> - 若返回
Some<TB>,则用TA的属性和TB的属性构造TC,转为Right<TC>
- 调用TA的
- 不能使用
.Sequence()方法,必须保留每个处理失败项的独立错误信息
遇到的问题:
- 用BindT转换器时,丢失了原TA的作用域,无法在错误信息或TC构造中引用TA的属性
- 尝试LINQ查询写法时,因嵌套Either类型导致编译错误
相关类型定义:
record TA(IEnumerable<TB> ListOfTB, int Prop1, string Prop2) { Option<TB> Find(Func<TB, bool> predicate) } record TB(int Prop3, string Prop4); IEnumerable<Either<Error, TA>> originalListOfEithers;
尝试过的代码示例:
// BindT写法,丢失TA作用域 var foundTs = ta.BindT(a => a.ListOfTB.Find(predicate).ToEither(Error.New($"Couldn't find TB for {a.Prop2}")));
// LINQ写法,编译错误 var transformedListOfEithers = from ta in originalListOfEithers let tb = ta.ListOfTB.Find(predicate).ToEither(Error.New("TB could not be found for predicate")) from b in tb select new TC(ta.Prop1, b.Prop3);
解决方案
方法一:使用Select + Map + Flatten
通过嵌套Map处理层级关系,既保留原TA的作用域,又正确合并Either层级:
var transformedList = originalListOfEithers.Select(eitherTa => eitherTa.Map(ta => // 先把Find的Option转为带TA上下文的Either ta.Find(predicate) .ToEither(Error.New($"无法为 {ta.Prop2} 找到对应的TB")) // 再把成功的TB转为TC .Map(tb => new TC(ta.Prop1, tb.Prop3)) ).Flatten() // 把Either<Error, Either<Error, TC>>扁平化为Either<Error, TC> );
eitherTa.Map(...):只处理Right状态的TA,Left错误直接保留- 内层的
ToEither使用ta.Prop2生成错误信息,保留了原TA的上下文 Flatten()解决嵌套Either的问题,最终得到单层的Either结果
方法二:修正LINQ查询写法
正确解包外层Either,避免嵌套类型导致的编译错误:
var transformedList = from eitherTa in originalListOfEithers // 先解包外层Either,仅处理Right状态的TA,Left错误自动保留 from ta in eitherTa // 生成带TA上下文的Find结果Either let eitherTb = ta.Find(predicate).ToEither(Error.New($"无法为 {ta.Prop2} 找到对应的TB")) // 解包Find的Either,失败则转为Left错误 from tb in eitherTb // 构造TC并包装为Right状态 select Either<Error, TC>.Right(new TC(ta.Prop1, tb.Prop3));
from ta in eitherTa:自动处理Either的解包,原Left错误会被直接包含在最终结果中- 所有错误信息都关联了原TA的
Prop2,保留了独立错误的上下文 - 最终结果长度与原列表完全一致,每个元素的错误或成功状态都被正确保留
内容的提问来源于stack exchange,提问作者G. Startin
相关产品推荐
相关产品推荐

