In order to keep SimulatePlanApp.strMain small and readable, we are going to extract the code that is in charge of calling RetCalc.simulatePlan and return a human-readable string detailing the result of the simulation. We call this new function strSimulatePlan, and use it as shown in the following code:
def strSimulatePlan(returns: Returns, nbOfYearsSaving: Int, params: RetCalcParams)
: RetCalcResult[String] = {
RetCalc.simulatePlan(
returns = returns,
params = params,
nbOfMonthsSavings = nbOfYearsSaving * 12
).map {
case (capitalAtRetirement, capitalAfterDeath) =>
val nbOfYearsInRetirement = params.nbOfMonthsInRetirement / 12
s"""
|Capital after $nbOfYearsSaving years of savings:
${capitalAtRetirement.round}
|Capital after $nbOfYearsInRetirement years in retirement:
${capitalAfterDeath.round}
|""".stripMargin
}.toValidatedNel
}
The function takes the parsed arguments, calls simulatePlan, and transforms its result into a string. In order to keep the same type as our parsing functions, we declare the return type of the function to be RetCalcResult[String]. This is an alias for ValidatedNel[RetCalcError, String], but simulatePlan returns Either[RetCalcError, String]. Fortunately, cats provide .toValidatedNel method to easily convert Either to ValidatedNel.