1

我正在编写一个快速的 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没有 lambda 的情况下调用。我想像这样部分应用ids它:ids |> Seq.map measureSelectTimes但是我不知道如何处理生成的部分应用函数然后映射到cmds. 这个的语法是什么?

4

3 回答 3

9

您可以使用Seq.map2

Seq.map2 measureSelectTimes ids cmds

或者

(ids, cmds) ||> Seq.map2 measureSelectTimes
于 2011-05-25T17:57:04.540 回答
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 ]
于 2011-05-25T17:53:51.840 回答
0

一种方法是将签名更改measureSelectTimes

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

然后您可以将map呼叫更改为

let results = input |> Seq.map measureSelectTimes
// or
let results = Seq.map measureSelectTimes input
于 2011-05-25T17:56:36.920 回答