# haskell – Compute a Working Capital Loan

This code takes a list of EBITDA amounts (for a hypothetical business), and computes a loan that would fund that business with working capital in periods of loss. When the business has positive EBITDA again, the loan is paid off. The loan also charges interest.

Some specific questions I have

• I am not sure the way `wcLoanCalc` calls `wcLoanR` is the most beautiful solution. Is there something more elegant I could do?
• It feels awkward to have such huge statements to update the `LoanPeriod` type, but I like having a single type name and hold all this data. Is there a better way?
• Is there a more general way I could implement printing out the table? Presumably there is some nice library for doing this

I’m grateful for any and all feedback!

``````-- Compute Working Capital Loan using Haskell

import Data.List
import Text.Printf

-- | Hold all information about a single period of loan amortization
data LoanPeriod = LoanPeriod
{ cashAvail :: Double
, draw      :: Double
, ds        :: Double
, principal :: Double
, interest  :: Double
, balance   :: Double
}

instance Show LoanPeriod
where
show lp = printf "%-10.2f %-10.2f %-10.2f %-10.2f %-10.2f %-10.2f"
(cashAvail lp)
(draw lp)
(ds lp)
(principal lp)
(interest lp)
(balance lp)

type WCLoanAmort = (LoanPeriod)

-- | Test the wcLoanCalc function
wcLoanTest :: WCLoanAmort
wcLoanTest = wcLoanCalc testEbitda testInterestRate
where
testEbitda = (100.0, 30.0, -50.0, -10.0, 20.0, 40.0, 60.0, -100.0, 120.0, 30.0)
testInterestRate = 0.12

-- | Print the result of the wcLoanTest
wcLoanTestPrint :: IO ()
wcLoanTestPrint = loanTable wcLoanTest

-- | Print out a WCLoanAmort as a table
loanTable :: WCLoanAmort -> IO ()
loanTable lpList =
putStrLn \$
printf "%-10s %-10s %-10s %-10s %-10s %-10sn"
"Cash" "Draw" "DS" "Prin" "Int" "Bal" ++
concat ("---------- " | x <- (1..6)) ++ "n" ++
concat (show lp ++ "n" | lp <- lpList)

-- | Calculate a working capital loan
wcLoanCalc :: (Double) -> Double -> WCLoanAmort
wcLoanCalc ebitda interestRate =
wcLoanR ebitda interestRate ()

-- | Recursively compute each period of working-capital loan
wcLoanR :: (Double) -> Double -> WCLoanAmort -> WCLoanAmort
wcLoanR (ebitda:es) interestRate loanData
| es == () = newLoanData
| otherwise = wcLoanR es interestRate newLoanData
where
startBalance  = case length loanData of
0 -> 0.0
_ -> balance (last loanData)
newInterest   = startBalance * interestRate / 12.0
newDraw       = - min ebitda 0.00
newDS         = max 0.0 \$ min ebitda (startBalance + newInterest)
newPrincipal  = newDS - newInterest
newBalance    = startBalance + newDraw - newPrincipal
newLoanData   = loanData ++ (newLoanPeriod)
newLoanPeriod = LoanPeriod
{ cashAvail = ebitda
, draw      = newDraw
, ds        = newDS
, principal = newPrincipal
, interest  = newInterest
, balance   = newBalance}
``````