While this does not directly address the issue of how to solve the larger problem with refactoring, reducing the amount and complexity of code should make it simpler to do that. Here are a couple of suggestions on how to do this (I don't have an F# compiler handy so please excuse any errors).
I would change
let dividendQuarter (t : Time) =
let currMonth = Time.month t
match c.DividendGroup with
| DividendGroup.Tele ->
if currMonth = 3 then 4
else if currMonth = 6 then 1
else if currMonth = 9 then 2
else if currMonth = 12 then 3
else 0
| _ ->
if currMonth = 2 then 4
else if currMonth = 5 then 1
else if currMonth = 8 then 2
else if currMonth = 11 then 3
else 0
to
let dividendQuarter (t : Time) =
match c.DividendGroup with
| DividendGroup.Tele ->
match Time.month t with
| 3 -> 4
| 6 -> 1
| 9 -> 2
| 12 -> 3
| _ -> 0
| _ ->
match Time.month t with
| 2 -> 4
| 5 -> 1
| 8 -> 2
| 11 -> 3
| _ -> 0
or
let dividendQuarter (t : Time) =
match (c.DividendGroup, Time.month t) with
| (DividendGroup.Tele, 3) -> 4
| (DividendGroup.Tele, 6) -> 1
| (DividendGroup.Tele, 9) -> 2
| (DividendGroup.Tele, 12) -> 3
| (_, 2) -> 4
| (_, 5) -> 1
| (_, 8) -> 2
| (_, 11) -> 3
| _ -> 0
according to taste.
You have a number of functions with the same pattern, for example:
let openingBalanceShareCapital =
memoise2 (fun closingBalanceShareCapital (t : Time) ->
if (t - 1).IsForecast then
closingBalanceShareCapital
else
- balanceSheet.ShareCapital (t - 1)
- balanceSheet.SharePremium (t - 1)
)
I would change those to something like this (maybe this idea can be applied in other areas as well):
let opening balance t =
let transformed =
memoise2 (fun closing (t : Time) ->
if (t - 1).IsForecast then
closing
else
balance t
)
transformed
let balanceCash t =
balanceSheet.Cash (t - 1)
let alanceIntercompanyDebt t =
balanceSheet.IntercompanyLoan (t - 1)
let alanceRetainedEarnings t =
- balanceSheet.RetainedEarnings (t - 1)
let balanceShareCapital t =
- balanceSheet.ShareCapital (t - 1) - balanceSheet.SharePremium (t - 1)
let openingBalanceCash = opening balanceCash t
let openingBalanceIntercompanyDebt = opening alanceIntercompanyDebt t
let openingBalanceRetainedEarnings = opening alanceRetainedEarnings t
let openingBalanceShareCapital = opening balanceShareCapital t
With regards to Company
, IntercoTimeSeries
and DividendTrappedCashSolver
, you could put them in a single record, reducing the amount of parameters you have to pass around.