You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用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>
  • 不能使用.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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 21:40:33