Применение Seq.map с использованием 2 последовательностей к методу, который принимает 2 параметра - PullRequest
1 голос
/ 25 мая 2011

Я пишу быстрый тестовый тест DB и выбрал F #, чтобы получить больше практики.

Я создал метод, measureSelectTimes, который имеет подпись Guid list * Guid list -> IDbCommand -> TimeSpan * TimeSpan.

Тогда я называю это:

let runTests () =
    let sqlCeConn : IDbConnection = initSqlCe() :> IDbConnection
    let sqlServerConn : IDbConnection = initSqlServer() :> IDbConnection
    let dbsToTest = [ sqlCeConn; sqlServerConn ]
    let cmds : seq<IDbCommand> = dbsToTest |> Seq.map initSchema
    let ids : seq<Guid list * Guid list> = cmds |> Seq.map loadData
    let input = Seq.zip ids cmds
    let results = input |> Seq.map (fun i -> measureSelectTimes (fst i) (snd i))
    // ...

Я явно аннотировал типы для пояснения.

Я не могу понять, как позвонить measureSelectTimes без лямбды. Я хотел бы частично применить ids к нему следующим образом: ids |> Seq.map measureSelectTimes, но тогда я не знаю, что делать с результирующими частично примененными функциями, чтобы затем отобразить на cmds. Какой синтаксис для этого?

Ответы [ 3 ]

8 голосов
/ 25 мая 2011

Вы можете использовать Seq.map2:

Seq.map2 measureSelectTimes ids cmds

Или

(ids, cmds) ||> Seq.map2 measureSelectTimes
3 голосов
/ 25 мая 2011

Ваша measureSelectTimes функция принимает два аргумента в качестве отдельных аргументов, но вместо этого вам нужна функция, которая принимает их как кортеж.Один из вариантов - просто изменить функцию на кортеж (если это логично для аргументов, которые будут кортежироваться).

Альтернативно, вы можете написать коинатор, который превращает функцию, принимающую два аргумента, в функцию, принимающую кортеж,Обычно это называется uncurry и существует на каком-то функциональном языке:

let uncurry f (a, b) = f a b

Тогда вы можете написать:

input |> Seq.map (uncurry measureSelectTimes)

Это выглядит хорошо для простого использования, как это, но яСчитаю, что слишком много использовать комбинаторы в F # - не очень хорошая идея, поскольку затрудняет чтение кода для менее опытных функциональных программистов.Я, вероятно, написал бы что-то вроде этого (потому что я нахожу это более читабельным):

[ for (time1, time2) in input -> measureSelectTimes time1 time2 ]
0 голосов
/ 25 мая 2011

Один из подходов состоит в том, чтобы изменить подпись measureSelectTimes на

(Guid list * Guid list) * IDbCommand -> TimeSpan * TimeSpan

Затем вы можете изменить map вызов на

let results = input |> Seq.map measureSelectTimes
// or
let results = Seq.map measureSelectTimes input
...