Hi Imran,
In case you can't construct a T unless you have the heart rate, one idea I had was to use withGood make an intermediate function that given the heartRate could produce a Person. Here's a working example:
case class Person(name: String, age: Int, heartRate: Int)
def parseName(input: String): String Or One[ErrorMessage] = {
val trimmed = input.trim
if (!trimmed.isEmpty) Good(trimmed) else Bad(One(s""""${input}" is not a valid name"""))
}
def parseAge(input: String): Int Or One[ErrorMessage] = {
try {
val age = input.trim.toInt
if (age >= 0) Good(age) else Bad(One(s""""${age}" is not a valid age"""))
}
catch {
case _: NumberFormatException => Bad(One(s""""${input}" is not a valid integer"""))
}
}
def parseHeartRate(input: String): Int Or One[ErrorMessage] = {
println("Executed expensive parseHeartRate method")
try {
val heartRate = input.trim.toInt
if (heartRate >= 0) Good(heartRate) else Bad(One(s""""${heartRate}" is not a valid heart rate"""))
}
catch {
case _: NumberFormatException => Bad(One(s""""${input}" is not a valid integer"""))
}
}
import Accumulation._
def parsePerson(inputName: String, inputAge: String, inputHeartRate: String): Person Or Every[ErrorMessage] = {
val name = parseName(inputName)
val age = parseAge(inputAge)
val heartRateToPerson = withGood(name, age) { (nm, ag) => (hr: Int) => Person(nm, ag, hr) }
for {
personWith <- heartRateToPerson
heartRate <- parseHeartRate(inputHeartRate)
} yield personWith(heartRate)
}
Here's some examples in the REPL:
scala> parsePerson("Fred", "22", "99")
Executed expensive parseHeartRate method
res0: org.scalactic.Or[Person,org.scalactic.Every[org.scalactic.ErrorMessage]] = Good(Person(Fred,22,99))
scala> parsePerson("Fred", "22", "oops")
Executed expensive parseHeartRate method
res1: org.scalactic.Or[Person,org.scalactic.Every[org.scalactic.ErrorMessage]] = Bad(One("oops" is not a valid integer))
scala> parsePerson("Fred", "-22", "oops")
res2: org.scalactic.Or[Person,org.scalactic.Every[org.scalactic.ErrorMessage]] = Bad(One("-22" is not a valid age))
scala> parsePerson("", "-22", "oops")
res3: org.scalactic.Or[Person,org.scalactic.Every[org.scalactic.ErrorMessage]] = Bad(Many("" is not a valid name, "-22" is not a valid age))