Reputation: 27429
I'm writing a quick DB perf test, and chose F# so I can get more practice.
I've created a method, measureSelectTimes
, which has the signature Guid list * Guid list -> IDbCommand -> TimeSpan * TimeSpan
.
Then, I call it:
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))
// ...
I've annotated explicitly with types to clarify.
What I can't figure out is how to call measureSelectTimes
without the lambda. I'd like to partially apply the ids
to it like this: ids |> Seq.map measureSelectTimes
but then I don't know what to do with the resulting partially applied functions to then map onto the cmds
. What's the syntax for this?
Upvotes: 1
Views: 1679
Reputation: 243106
Your measureSelectTimes
function takes two arguments as separate arguments, but you instead need a function that takes them as a tuple. One option is to just change the function to take a tuple (if it is logical for the arguments to be tupled).
Alternative, you can write a cobinator that turns a function taking two arguments into a function taking tuple. This is usually called uncurry
and it exists in some functional language:
let uncurry f (a, b) = f a b
Then you can write:
input |> Seq.map (uncurry measureSelectTimes)
This looks okay for a simple use like this, but I think that using combinators too much in F# is not a good idea as it makes code difficult to read for less experienced functional programmers. I would probably write something like this (because I find that more readable):
[ for (time1, time2) in input -> measureSelectTimes time1 time2 ]
Upvotes: 3
Reputation: 55195
You can use Seq.map2
:
Seq.map2 measureSelectTimes ids cmds
Or
(ids, cmds) ||> Seq.map2 measureSelectTimes
Upvotes: 9
Reputation: 62985
One approach is to change the signature of measureSelectTimes
to
(Guid list * Guid list) * IDbCommand -> TimeSpan * TimeSpan
Then you can change the map
call to
let results = input |> Seq.map measureSelectTimes
// or
let results = Seq.map measureSelectTimes input
Upvotes: 0