Несоответствие типов с Async в F # - PullRequest
2 голосов
/ 26 февраля 2010

Я только начал возиться с F # и пытаюсь выполнить некоторые базовые параллельные вычисления, чтобы познакомиться с языком. У меня проблемы с несовпадением типов. Вот пример:

let allVariances list =
    seq {
        for combination in allCombinations list do
            yield (combination, abs(targetSum - List.sum combination))
    }

let compareVariance tup1 tup2 =
    if snd tup1 < snd tup2 then
        tup1
    else
        tup2

let aCompareVariance tup1 tup2 =
    async { return compareVariance tup1 tup2 }

let matchSum elements targetSum =
    allVariances elements
    |> Seq.reduce aCompareVariance
    |> Async.Parallel
    |> Async.RunSynchronously

Итак, «элементы allVariances» выдают последовательность <float list * float>. CompareVariance берет два из этих <float list * float> кортежей и возвращает один с меньшим вторым элементом (дисперсия). Моя цель - использовать Reduce, чтобы получить кортеж с наименьшей дисперсией. Однако я получаю несоответствие типов в аргументе aCompareVariance:

Ошибка 1 Несоответствие типов. Ожидается список с плавающей точкой * float -> список с плавающей точкой * float -> список с плавающей точкой * float, но с учетом списка с плавающей точкой * float -> список с плавающей точкой * float -> Async <float list * float> Тип 'список с плавающей точкой * float' не соответствует введите 'Async <float list * float>'

Похоже, что тип возврата Async не принимается Reduce?

1 Ответ

2 голосов
/ 26 февраля 2010

Seq.reduce принимает функцию и последовательность и сокращает список, используя функцию. То есть результат сокращения последовательности {a1;a2;a3;...;an} с помощью функции f будет f(f(...f(f(a1,a2),a3),...),an))...). Однако передаваемая вами функция не может быть применена таким образом, поскольку тип возвращаемого значения (Async<float list * float>) не соответствует типам аргумента (float list * float). Что именно вы пытаетесь достичь?

Также имейте в виду, что вычисления async отлично подходят для асинхронной работы, но не идеальны для параллельной работы. См. F #: Асинхронизация, Задачи и PLINQ, о, боже! и Параллельная библиотека задач и асинхронные рабочие процессы .

EDIT

Вот один из способов написать функцию, которая будет уменьшать количество элементов больше, чем вы ожидаете, работая примерно так:

[|a1; a2; a3; a4|]
[|f a1 a2; f a3 a4|]
f (f a1 a2) (f a3 a4)

На каждом этапе все применения f будут выполняться параллельно. При этом используется Async.Parallel, что, как упоминалось выше, вероятно, менее целесообразно, чем использование библиотеки параллельных заданий (и даже может быть медленнее, чем обычная синхронная Array.reduce). Таким образом, просто подумайте, что это демонстрационный код, показывающий, как собрать вместе асинхронные функции.

let rec reduce f (arr:_[]) =
  match arr.Length with
  | 0 -> failwith "Can't reduce an empty array"
  | 1 -> arr.[0]
  | n ->
      // Create an array with n/2 tasks, each of which combines neighboring entries using f
      Array.init ((n+1)/2) 
        (fun i -> 
           async { 
             // if n is odd, leave last item alone
             if n = 2*i + 1 then
               return arr.[2*i]
             else
               return f arr.[2*i] arr.[2*i+1]}) 
      |> Async.Parallel |> Async.RunSynchronously
      |> reduce f

Обратите внимание, что преобразование элементов в значения Async и обратно все происходит внутри этой функции, поэтому она имеет тот же тип, что и Array.reduce, и будет использоваться с обычной функцией compareVariance, а не с aCompareVariance.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...