Comparitive LoanCalc

From dis-Emi-A

Jump to: navigation, search


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);
  }
}
Personal tools