languageext eitherasyn с растущей связью с проверкой - PullRequest
0 голосов
/ 09 февраля 2019

Я использую язык lauthy ext в . Вот 3 функции, которые будут вызываться в главной функции формы. Цель - вернуть агрегированные результаты команд .. или Ошибка, но она ниже, когда я передаю yв ExecuteSingleHostCommands

Ошибка CS1503 Аргумент 1: невозможно преобразовать из 'System.Func>' в 'System.Func>' 03 '

  1. ВозвращаетFun для данной команды

  2. выполняет fun с параметром и возвращает результаты или ошибку

  3. проверяет и возвращает ошибку в случае неудачи - Main func - выполняет однуодной командой и выручает, если какая-либо команда плохая .. если все идет хорошо, возвращает агрегированные результаты всех команд

    внутренний статический Func> GetSingleCommands (IDictionary >> commandMap, Command hostCommand) => commandMap.Where (command=> command.Key == hostCommand.Name) .Select (keyValuePairs => keyValuePairs.Value) .FirstOrDefault ();

    внутренняя статическая EitherAsync> ExecuteSingleCommands (Func> команды, string hostCommand) => новый список >> {команды} .Aggregate (Right> (ImmutableList.Empty) .ToAsync (), (state, func) => state.Bind (response => func (hostCommand) .Map (response.Добавить)));

    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);
    

1 Ответ

0 голосов
/ 10 февраля 2019

Я думаю, вам следует уделить больше внимания этому вопросу.Почти невозможно понять, о чем вы спрашиваете здесь, и здесь отсутствуют функции GetSingleHostCommands и типы (и вы даже пишете мое имя неправильно;))

В любом случае, из того, что я могу вывести из вашего примера, выесть пара проблем:

  • В ExecuteAllAsync вы смешиваете несколько монадических типов в одном выражении LINQ.Это не то, как работают LINQ или монады.Вы должны пытаться поддерживать один и тот же монадический тип на протяжении всего пути.Итак, hostCommands - это IEnumerable монада, Command.Validate(hostCommand.Name) - это Either монада

  • Похоже, у вас возникла проблема с дублированием из-за типа результата Response иHostResponse.Это можно сделать универсальным.

  • GetSingleCommands не будет использовать словарь, потому что он повторяется каждый раз.

  • ExecuteSingleCommands делает слишком много работы.Все, что он должен сделать, это вызвать делегата с помощью предоставленной команды.

Похоже, вы слишком обдумали это, и вы можете попытаться сделать шаг назад и упростить свой подход.При функциональном программировании следует помнить, что всегда следует за типами .Типы всегда приведут вас к истине.

Итак, первое, что нужно сделать, это разгадать.Это реализация, которую я сделал, и я думаю, что она соответствует вашим намерениям.Я удалил использование Dictionary для lanuguage-ext Map и IList и ImmutableList для языка-ext Seq.Главным образом потому, что с ними легче работать, но также легче смотреть в коде.

    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выражение работает по одной команде.Это запускает проверку, затем получает команду, затем выполняет ее и затем возвращает результат.

Также обратите внимание, что первые две строки выражения LINQ изменяют свой результат с Either на EitherAsync, используя .ToAsync().Итак, каждая строка выражения LINQ работает с одной и той же монадой: EitherAsync.

Карта соберет в Seq<EitherAsync<Error, R>>, что является неправильным результатом для функции, EitherAsync равно внутри Seq, но мы хотим, чтобы он был снаружи .Это то, что делает вызов .Sequence().Превращает Seq<EitherAsync<Error, R>> в EitherAsync<Error, Seq<R>>.

...