I'm writing a larger project in F# where performance is critical. The core structure as of now is 19 functions all with the same signature: parameters -> record -> Result(Record, Error) and an appropriate composition/binding of these ensuring that the record produced by the previous function is used in the next. The parameters are never overwritten and so they are the same in all the 19 function calls. Here the "final" function:
let execution parameters record =
let (>==) m f = Result.bind (f parameters) m
record
|> stepOne parameters
>== stepTwo
>== stepThree
My questions is: Would it be better in terms of performance (or style) to define the steps as subfunctions of "execution" with type record -> record, so that the same parameters do not have to be passed 19 times through different functions? It also allows for code that relies on specific parameters (the parameters are a record type) in stead of all parameters at once. On the other hand these subfunctions cannot be reused outside of this context (which I do not think, they ever will) and it might make unit testing harder. In my case it would also mean a very long execution-funtion which may not be desirable. Any input is much appreciated!
CodePudding user response:
"Would it be better in terms of performance (or style) to define the steps as subfunctions of "execution" with type record -> record, so that the same parameters do not have to be passed 19 times through different functions?"
Most certainly yes. Just write it that way and profile it.
More general:
It takes a bit to get into a good F# programming style, reading books or good code repositories helps to get there.
Your code uses "railway oriented programming", best explained by Scott Wlaschin: https://fsharpforfunandprofit.com/rop/
This style of programming is nice but certainly not appropriate for high performance loops. But even in highly performance sensitive programs, only 5% of the code is in the high performance loop. So there is much room for pretty design patterns. Optimizing the core performance code can only be done for the concrete case. And the technique is try and profile at first. If the code you mention is really in the performance critical path then your measurements will show that avoidance of function calls and parameter passing leads to faster code.