I'm wanting to write a big chunk of C# code using immutable F#. It's a device monitor, and the current implementation works by constantly getting data from a serial port and updating member variables based on new data. I'd like to transfer that to F# and get the benefits of immutable records, but my first shot at a proof-of-concept implementation is really slow.
open System
open System.Diagnostics
type DeviceStatus = { RPM : int;
Pressure : int;
Temperature : int }
// I'm assuming my actual implementation, using serial data, would be something like
// "let rec UpdateStatusWithSerialReadings (status:DeviceStatus) (serialInput:string[])".
// where serialInput is whatever the device streamed out since the previous check: something like
// ["RPM=90","Pres=50","Temp=85","RPM=40","Pres=23", etc.]
// The device streams out different parameters at different intervals, so I can't just wait for them all to arrive and aggregate them all at once.
// I'm just doing a POC here, so want to eliminate noise from parsing etc.
// So this just updates the status's RPM i times and returns the result.
let rec UpdateStatusITimes (status:DeviceStatus) (i:int) =
match i with
| 0 -> status
| _ -> UpdateStatusITimes {status with RPM = 90} (i - 1)
let initStatus = { RPM = 80 ; Pressure = 100 ; Temperature = 70 }
let stopwatch = new Stopwatch()
stopwatch.Start()
let endStatus = UpdateStatusITimes initStatus 100000000
stopwatch.Stop()
printfn "endStatus.RPM = %A" endStatus.RPM
printfn "stopwatch.ElapsedMilliseconds = %A" stopwatch.ElapsedMilliseconds
Console.ReadLine() |> ignore
This runs in about 1400 ms on my machine, whereas the equivalent C# code (with mutable member variables) runs in around 310 ms. Is there any way to speed this up without losing the immutability? I was hoping that the F# compiler would notice that initStatus and all the intermediate status variables were never reused, and thus simply mutate those records behind the scene, but I guess not.