问题描述
|
我正在编写一个快速的数据库性能测试,并选择了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
。这是什么语法?
解决方法
您可以使用
Seq.map2
:
Seq.map2 measureSelectTimes ids cmds
要么
(ids,cmds) ||> Seq.map2 measureSelectTimes
,您的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”的签名更改为
(Guid list * Guid list) * IDbCommand -> TimeSpan * TimeSpan
然后您可以将the17ѭ呼叫更改为
let results = input |> Seq.map measureSelectTimes
// or
let results = Seq.map measureSelectTimes input