languageext eitherasyn 与聚合绑定与验证

languageext eitherasyn with aggegrate bind with validation

我在 中使用 lauthy 语言 ext 这里有 3 个函数将在主函数中调用 目的是 return 命令的聚合结果.. 或错误但是当我将 y 传递给 ExecuteSingleHostCommands

Error CS1503 Argument 1: cannot convert from 'System.Func>' to 'System.Func>' 03'

  1. Returns 给定命令的乐趣

  2. 使用参数和 return 结果或错误执行乐趣

  3. 验证和 return 错误失败 -- Main func - 一个接一个地执行命令,如果有任何命令是错误的,则退出。如果一切顺利return 所有命令的汇总结果

    内部静态函数> GetSingleCommands( IDictionary>> commandMap, 命令 hostCommand) => commandMap.Where(命令 => command.Key == hostCommand.Name).Select(keyValuePairs => keyValuePairs.Value).FirstOrDefault();

    内部静态 EitherAsync> ExecuteSingleCommands( Func> 命令,字符串 hostCommand) => 新列表>> {命令}.Aggregate( 右>(ImmutableList.Empty).ToAsync(), (state, func) => state.Bind(response => func(hostCommand).Ma​​p(response.Add)));

    internal static Either<Error, Unit> Validate(string hostCommand) =>
    CommandMap.Find(command => command.Key == hostCommand).IsSome ? Right(Unit.Default) : Left<Error, Unit>(new Error());
    
    public static EitherAsync<Error, ImmutableList<Response>> ExecuteAllAsync(
    IDictionary<string, Func<string, EitherAsync<Error, HostResponse>>> commandMap, IList<Command> hostCommands) =>
    from hostCommand in hostCommands
    from x in Command.Validate(hostCommand.Name)
    let y = Command.GetSingleHostCommands(commandMap, hostCommand).ToAsync()
    select Command.ExecuteSingleHostCommands(y, hostCommand.jobName);
    

我认为你应该多注意这个问题。几乎不可能理解你在这里问什么,而且缺少函数 GetSingleHostCommands 和类型(你甚至拼错了我的名字 ;) )

无论如何,从你的例子中我可以推断出你有几个问题:

  • ExecuteAllAsync 中,您在一个 LINQ 表达式中混合了多个 monadic 类型。这不是 LINQ 或 monad 的工作方式。您必须始终尝试保持相同的单子类型。所以,hostCommands 是一个 IEnumerable monad,Command.Validate(hostCommand.Name) 是一个 Either monad

  • 由于 ResponseHostResponse 的结果类型,您似乎遇到了重复问题。这可以做成通用的。

  • GetSingleCommands 不会使用字典,因为它每次都会遍历它。

  • ExecuteSingleCommands 做了太多工作。它所要做的就是使用提供的命令调用委托。

看来您想多了,您可能想尝试退后一步并简化您的方法。函数式编程要记住的一件事是 始终遵循类型 。类型将始终引导您了解真相。

所以,首先要做的就是解决这个问题。这是我完成的一个实现,我认为它非常符合您的意图。我已经删除了对 lanuguage-ext Map 使用 Dictionary 和对语言扩展 Seq 使用 IListImmutableList。主要是因为它们更易于使用,而且在代码中也更易于查看。

    public class Command {

        public readonly string Name;

        static Either<Error, Func<string, EitherAsync<Error, R>>> GetCommand<R>(
            Map<string, Func<string, EitherAsync<Error, R>>> commandMap, 
            Command hostCommand) =>
                 commandMap.Find(hostCommand.Name)
                           .ToEither(new Error());

        internal static EitherAsync<Error, R> ExecuteCommand<R>(
            Func<string, EitherAsync<Error, R>> command,
            Command cmd) =>
                command(cmd.Name);

        static Either<Error, Unit> Validate<R>(
            Map<string, Func<string, EitherAsync<Error, R>>> commandMap, 
            Command hostCommand) =>
                commandMap.Find(hostCommand.Name)
                          .Map(_ => unit)
                          .ToEither(new Error());

        public static EitherAsync<Error, Seq<R>> ExecuteAllAsync<R>(
            Map<string, Func<string, EitherAsync<Error, R>>> commandMap,
            Seq<Command> hostCommands) =>
                hostCommands.Map(cmd =>
                    from _ in Command.Validate(commandMap, cmd).ToAsync()
                    from f in Command.GetCommand<R>(commandMap, cmd).ToAsync()
                    from r in Command.ExecuteCommand(f, cmd)
                    select r)
                   .Sequence();
    }

您可能会从 ExecuteAllAsync 中注意到,现在正在映射 hostCommands,在单个命令上使用内部 LINQ 表达式 运行。这将运行验证,然后获取命令,然后执行它,然后 returns 结果。

另请注意,LINQ 表达式的前两行使用 .ToAsync() 将其结果从 Either 转换为 EitherAsync。因此,LINQ 表达式的每一行都使用相同的 monad:EitherAsync.

地图将收集到 Seq<EitherAsync<Error, R>>,这是函数的错误结果,EitherAsync 内部 Seq,但我们希望它在 外面 。这就是对 .Sequence() 的调用所做的。它将 Seq<EitherAsync<Error, R>> 变成 EitherAsync<Error, Seq<R>>.