使用2个序列将Seq.map应用于采用2个参数的方法

时间:2011-05-25 17:50:16

标签: f# seq partial-application

我正在编写一个快速的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))
    // ...

我已明确注释了要澄清的类型。

我无法弄清楚如何在没有lambda的情况下调用measureSelectTimes。我想将ids部分应用于此ids |> Seq.map measureSelectTimes,但后来我不知道如何处理生成的部分应用函数,然后映射到cmds。这是什么语法?

3 个答案:

答案 0 :(得分:8)

您可以使用Seq.map2

Seq.map2 measureSelectTimes ids cmds

或者

(ids, cmds) ||> Seq.map2 measureSelectTimes

答案 1 :(得分:3)

您的measureSelectTimes函数将两个参数作为单独的参数,但您需要一个将它们作为元组的函数。一种选择是只更改函数以获取元组(如果参数被逻辑化是合乎逻辑的)。

或者,您可以编写一个cobinator,将一个带有两个参数的函数转换为一个带元组的函数。这通常称为uncurry,它以某种函数语言存在:

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

然后你可以写:

input |> Seq.map (uncurry measureSelectTimes)

对于像这样的简单使用看起来没问题,但我认为在F#中使用组合器太多不是一个好主意,因为它使代码难以为经验不足的函数式程序员阅读。我可能会写这样的东西(因为我发现它更具可读性):

[ for (time1, time2) in input -> measureSelectTimes time1 time2 ]

答案 2 :(得分:0)

一种方法是将measureSelectTimes的签名更改为

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

然后,您可以将map调用更改为

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