2011-05-25 61 views
1

我正在写一个快速数据库性能测试,并选择了F#以便我可以获得更多练习。将2个序列应用Seq.map到一个需要2个参数的方法

我已经创建了一个方法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。这是什么语法?

+1

顺便说一句,你可以写你的lambda作为'(乐趣(ID,CMD) - > measureSelectTimes ID CMD)'。 (这与问题无关) – Dmitry 2011-05-25 18:51:06

+0

@Dmitry - 谢谢,好东西。这就是为什么我发布这个问题,我需要扩展我的F#词汇。 – codekaizen 2011-05-25 19:31:20

回答

8

您可以使用Seq.map2

Seq.map2 measureSelectTimes ids cmds 

或者

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

'let partial = Seq.map2 measureSelectTimes IDs'的确如此。当你看到解决方案时,它非常明显而且容易。但在我看到它之前,它甚至没有跨过我的想法。 :-(+1 – Dmitry 2011-05-25 18:42:00

+0

这就是我一直在寻找的东西;我没有看到Seq.map2是如何工作的,但是这个清除了它。还要感谢@Dmitry如何将结果表达为部分应用,这正是我最终想到的。 +1 – codekaizen 2011-05-25 19:54:27

+2

+1教我一个新的操作员 - “||>”是从哪里来的?它不在[MSDN](http://msdn.microsoft.com/zh-cn/library/dd233228.aspx)页面上。 – Samuel 2011-05-25 23:48:01

3

您的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

感谢您的答案和使用uncurry函数和列表理解来解决它的2个新工具。另外,感谢这本书。 – codekaizen 2011-05-25 19:56:39

0

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

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

然后你可以map电话更改为

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

是的,我想到了这一点,但我知道必须有另一种方法,而不是需要改变方法信号。 – codekaizen 2011-05-25 19:29:12

相关问题