The problem isn't really in the fact that you have moreComplicatedLogic
in the middle (and so it is inconvenient to write big let rec
). The problem is that your code is implementing Dynamic Programming algorithm in an inefficient way.
The recursive calls end up calling cashClosingBalance
multiple times with the same argument (rather than calling it just once and storing the result in some local cache). In functional programming you can solve this using a fairly general concept of memoization but you might be able to rewrite your algorithm differently to make it more efficient.
If you want to use memoization, then you need something like this - the following helper takes a function and creates a function of the same type which caches the results of previous calls:
let memoize f =
let dict = System.Collections.Generic.Dictionary<_, _>()
fun v ->
match dict.TryGetValue(v) with
| true, res -> res
| _ ->
let res = f v
dict.Add(v, res)
res
Then you can rewrite your code using memoize
like this (I simply wrapped all function definitions in memoize
and changed the order of arguments so that t
is the last one):
let cashOpeningBalance cashClosingBalance = memoize (fun t ->
if t = 1 then
10.0
else
cashClosingBalance (t - 1))
let cashInterest cashClosingBalance = memoize (fun t ->
(cashOpeningBalance cashClosingBalance t) * 0.03 )
let accumulatedCash cashClosingBalance = memoize (fun t ->
(cashOpeningBalance cashClosingBalance t) + (cashInterest cashClosingBalance t))
// let moreComplicatedLogic t cashClosingBalance = ...
let rec cashClosingBalance = memoize (fun t ->
//accumulatedCash t cashClosingBalance
let temp = accumulatedCash cashClosingBalance t
printfn "Cash Closing Balance = %f Where t = %i" temp t
temp)