In my code, I very often need to process a list by performing operations on an internal model. For each processed element, the model is returned and then a 'new' model is used for the next element of the list.
Usually, I implement this by using a tail recursive method:
def createCar(myModel: Model, record: Record[Any]): Either[CarError, Model] = {
record match {
case c: Car =>
// Do car stuff...
val newModel: Model = myModel.createCar(record)
Right(newModel)
case _ => Left(CarError())
}
}
@tailrec
def processCars(myModel: Model, records: List[Record[Any]]): Either[CarError, Model] =
records match {
case x :: xs =>
createCar(myModel, x) match {
case Right(m) => processCars(m, xs)
case e@Left(_) => e
}
case Nil => Right(myModel)
}
Since I keep repeating this kind of pattern, I am searching for ways to make it more concise and more functional (i.e., the Scala way).
I have looked into foldLeft, but cannot get it to work with Either:
recordsList.foldLeft(myModel) { (m, r) =>
// Do car stuff...
Right(m)
}
Is foldLeft a proper replacement? How can I get it to work?
Following up on my earlier comment, here's how to
unfold()to get your result. [Note: Scala 2.13.x]The advantage here is:
recordsstops after the 1stLeftis returned or after all the records have been processed, whichever comes first.LazyList, and nothing is holding on to the head of the resulting list, every element except thelastshould be immediately released for garbage collection.