Comparitive LoanCalc
From dis-Emi-A
Using Stephane's OCAML code from [[1]] as a base (TODO: Check back for changes, add interwiki link). This obviously has a few problems as far as functional programming goes, but the biggest problem (parsing args) doesn't seem correctable at the moment.
Contents |
OCAML
type retirement = { year: int; principal: float; allowance: float };;
let print aretirement =
Printf.sprintf "year:%03d principal:%f allowance:%f" aretirement.year aretirement.principal aretirement.allowance;;
let tax_rate = 0.35;;
let tax_free_income = 1421.0;;
let arg_yield = ref 0.0;;
let arg_inflation = ref 0.0;;
let arg_principal = ref 0.0;;
let arg_year_count = ref 0;;
let arg_allowance = ref 0.0;;
let args_spec = [
("-yield", Arg.Set_float arg_yield, "Bond yield");
("-years", Arg.Set_int arg_year_count, "Year count");
("-inflation", Arg.Set_float arg_inflation, "Monthly allowance increase each year");
("-principal", Arg.Set_float arg_principal, "The initial lump sum");
("-allowance", Arg.Set_float arg_allowance, "Monthly allowance")];;
Arg.parse args_spec (function x -> ()) "Grand Unified Retirement Calculator";;
let year_count = !arg_year_count;;
assert (year_count > 1);;
let yield = !arg_yield;;
let inflation = !arg_inflation;;
let monthly_allowance = !arg_allowance;;
let rec calculate_principal counter principal allowance year_count =
print_endline (print { year = counter; principal = principal; allowance = allowance });
if year_count = 1 then ()
else
let grossIncome = yield *. principal in
let taxableIncome = grossIncome -. tax_free_income in
let net_income = grossIncome -. (taxableIncome *. tax_rate) in
let reinvested_income = net_income -. (allowance *. 12.0) in
let new_principal = principal +. reinvested_income in
let new_allowance = allowance *. (1.0 +. inflation) in
calculate_principal (counter + 1) new_principal new_allowance (year_count - 1);;
calculate_principal 1 !arg_principal monthly_allowance !arg_year_count;;
NewLang
Straight-Forward Conversion
To show the most consistent representation.
tax_rate = 0.35;
tax_free_income = 1421.0;
calculate_principal :> counter, principal, allowance, yield, inflation, monthly_allowance : ? > 1 : year_count
{
//print output somehow (no ideas yet for this)
grossIncome = yield * principal;
taxableIncome = grossIncome - tax_free_income;
net_income = grossIncome - (taxableIncome * tax_rate);
reinvested_income = net_income - (allowance * 12);
new_principal = principal + reinvested_income;
new_allowance = allowance * (1 + inflation);
calculate_principal( counter+1, new_principal, new_allowance, yield, inflation, monhtly_allowance, year_count - 1 );
}
// terminal condition
calculate_principal :> counter, principal, allowance, yield, inflation, monthly_allowance, 1 /*year_count*/
{ }
// Entry point (do not specify counter on command-line)
calculate_principal :> principal, allowance, yield, inflation, monthly_allowance, year_count
-> calculate_principal( 0, principal, allowance, year_count );
The compiler must be told the entry point of "calculate_principal" and it will handle all parsing and error conditions. The constraint on year handles it's invalid input, and the 1 case handles the terminal condition.
Closure Version
A cleaned up version of what would be nicer (nobody likes passing state date around)
//our entry point (from command-line) which takes all arguments
ext_calculate_principal :> principal, allowance, yield, inflation, monthly_allowance, : ? > 1 :year_count
{
tax_rate = 0.35;
tax_free_income = 1421.0;
// declare recursive formula
calculate_principal :> counter, principal, allowance : ? > 1 : year_count
{
//print output somehow (no ideas yet for this)
grossIncome = yield * principal;
taxableIncome = grossIncome - tax_free_income;
net_income = grossIncome - (taxableIncome * tax_rate);
reinvested_income = net_income - (allowance * 12);
new_principal = principal + reinvested_income;
new_allowance = allowance * (1 + inflation);
calculate_principal( counter+1, new_principal, new_allowance, year_count - 1 );
}
// declare terminal condition
calculate_principal :> counter, principal, allowance, 1 /*year_count*/ { }
//perform calculation
calculate_principal( 1, principal, allowance, year_count );
}
Non-Recursive/Functional Form
The following would probably be the preferred solution for this problem (though the recursive is shown above since many problems can not easily be translated).
//our entry point (from command-line) which takes all arguments
calculate_principal :> principal, allowance, yield, inflation, monthly_allowance, : ? > 1 :year_count
{
tax_rate = 0.35;
tax_free_income = 1421.0;
[ cur_year as 1..year_count ]
{
//print output somehow (no ideas yet for this)
grossIncome = yield * principal;
taxableIncome = grossIncome - tax_free_income;
net_income = grossIncome - (taxableIncome * tax_rate);
reinvested_income = net_income - (allowance * 12);
principal = principal + reinvested_income;
allowance = allowance * (1 + inflation);
}
}
