Reputation: 12107
Let's imagine this recursive function:
let rec doSomething dataList b c d e f g h i =
// go through dataList and recurse with updated parameters
So we can make it cleaner:
type Context = { b:..; c:..; ... }
let rec doSomething dataList context =
// recurse with an updated context object
In practice this is slower since the context object has to be re-created every time and with very tight loops with simple calculations the overhead is visible.
I have several math loops done like this but now I have a new scenario coming up:
I need to use them on data that gets streamed in by using the same logic, but step by step as the data is coming.
So my function would be something like:
let doOneStepOfSomething oneData context : result * Context =
process one piece of data and returns the context object for the next iteration
But then I have also the object re-creation issue and I need to keep different contexts.
Is that a valid use case for a class where each instance could have its context variables as mutable? or would it make sense to make a mutable type with mutable fields instead for the context?
Upvotes: 1
Views: 97
Reputation: 243051
For any performance related question, the only answer is that you have to test it to see. I tested four different approaches using a simple function and the #time
feature.
type C = { a:int; b:int; c:int; d:int }
let rec foo c =
if c.a > 100000000 then c
else foo { a = c.a + 1; b = c.a; c = c.a; d = c.a }
foo { a=0; b=0; c=0; d=0 } // ~1.1 sec
let rec bar a b c d =
if a > 100000000 then (a,b,c,d)
else bar (a+1) a a a
bar 0 0 0 0 // ~200ms
[<Struct>]
type S(a:int,b:int,c:int,d:int) =
member x.A = a
member x.B = b
member x.C = c
member x.D = d
let rec goo (c:S) =
if c.A > 100000000 then c
else goo (S(c.A+1, c.A, c.A, c.A))
goo (S(0,0,0,0)) // ~1.6sec
type M = { mutable a:int; mutable b:int; mutable c:int; mutable d:int }
let rec zoo c =
if c.a > 100000000 then c
else
c.a <- c.a + 1
c.b <- c.a
c.c <- c.a
c.d <- c.a
zoo c
zoo { a=0; b=0; c=0; d=0 } // ~1 sec
From these four tests, it seems that inline parameters are more efficient than anything else (which is pretty much all the same). So I would just use an immutable record, which makes the code clear and optimize this only if it proved to be an issue more generally in your system.
Upvotes: 3