I would like to solicit some general design principles and best practices to avoid creating a callback pyramid of doom particularly in the Scala language.Consider the following rudimentary and imaginary code snippet:val response: Future[Either[ApiError, Option[CogWidget]]] = services.findCogWidget(Some-UUID-42)response.flatMap {  case Right(cogWidget) =>    val validationResponse: Future[Either[ApiError, ValidationResult]] = services.validateCogWidget(cogWidget)    validationResponse.flatMap {      case Right(validationResult) =>        val registerResult: Future[Either[ApiError, RegistrationTicket]] = services.cogWidgetRegisterRequest(cogWidget, validationResult)        registerResult.map {          case Right(ticket) =>            Some(:D -> ticket)          case _ => None        }      case x @ Left(_) => Future.successful(x)    }        case x @ Left(_) => Future.successful(x)}How could you rewrite this to avoid / eliminate the callback pyramid of doom effect?
Scala Callback Pyramid of Doom
functional programming;scala;callbacks