Payment(PaymentAmount(20), Currency.EUR, CardType.Visa, CardNumber("123")), Payment(PaymentAmount(-20), Currency.EUR, CardType.Visa, CardNumber("005")), Payment(PaymentAmount(30), Currency.EUR), Payment(PaymentAmount(-30), Currency.EUR)) val expectedSuccessfulAndUnsuccessfulPaymentValidations : List[Validation[Error,Payment]] = List(Success(Payment.unsafe(PaymentAmount.unsafe(10.0), Currency.USD, PaymentMethod.Check(CheckNumber.unsafe(15)))), Failure(Error(List("PaymentAmount cannot be negative: -10.0", "CheckNumber cannot be greater than 1,000,000: 2000000"))), Success(Payment.unsafe(PaymentAmount.unsafe(20.0), Currency.EUR, PaymentMethod.Card(CreditCardInfo(CardType.Visa,CardNumber.unsafe("123"))))), Failure(Error(List("PaymentAmount cannot be negative: -20.0", "CardNumber cannot be less than 111111: 005"))), Success(Payment.unsafe(PaymentAmount.unsafe(30.0), Currency.EUR, PaymentMethod.Cash)), Failure(Error(List("PaymentAmount cannot be negative: -30.0")))) // turn a list of partly failed payment validations into a failed validation of a list of payments val failedValidationOfPayments : Validation[Error,List[Payment]] = listTraverse.sequence(successfulAndUnsuccessfulPaymentValidations)(errorValidationApplicative) val expectedFailedValidationOfPayments : Validation[Error,List[Payment]] = Failure(Error(List("PaymentAmount cannot be negative: -10.0", "CheckNumber cannot be greater than 1,000,000: 2000000", "PaymentAmount cannot be negative: -20.0", "CardNumber cannot be less than 111111: 005", "PaymentAmount cannot be negative: -30.0"))) assert( successfulAndUnsuccessfulPaymentValidations == expectedSuccessfulAndUnsuccessfulPaymentValidations) assert(failedValidationOfPayments == expectedFailedValidationOfPayments) On this slide we revisit the previous two tests but include failed validations. This showcases how the Validation Applicative for Error is able to return Validation failures informing us of all constraint violations, rather than just one (the first one). Note that since sequence is defined in terms of the map2 function of the applicative that it is being passed, the sequence function benefits from the ability of said map2 function to combine failed validations and so the end result of sequencing is a single failure whose Error informs us of all constraint violations. val successfulAndUnsuccessfulPaymentValidations: List[Validation[Error,Payment]] = List(Payment(PaymentAmount(10), Currency.USD, CheckNumber(15)), Payment(PaymentAmount(-10), Currency.USD, CheckNumber(2_000_000)), Payment(PaymentAmount(20), Currency.EUR, CardType.Visa, CardNumber("123")), Payment(PaymentAmount(-20), Currency.EUR, CardType.Visa, CardNumber("005")), Payment(PaymentAmount(30), Currency.EUR), Payment(PaymentAmount(-30), Currency.EUR)) val expectedSuccessfulAndUnsuccessfulPaymentValidations : List[Validation[Error,Payment]] = List(Success(Payment.unsafe(PaymentAmount.unsafe(10.0), Currency.USD, PaymentMethod.Check(CheckNumber.unsafe(15)))), Failure(Error(List("PaymentAmount cannot be negative: -10.0", "CheckNumber cannot be greater than 1,000,000: 2000000"))), Success(Payment.unsafe(PaymentAmount.unsafe(20.0), Currency.EUR, PaymentMethod.Card(CreditCardInfo(CardType.Visa,CardNumber.unsafe("123"))))), Failure(Error(List("PaymentAmount cannot be negative: -20.0", "CardNumber cannot be less than 111111: 005"))), Success(Payment.unsafe(PaymentAmount.unsafe(30.0), Currency.EUR, PaymentMethod.Cash)), Failure(Error(List("PaymentAmount cannot be negative: -30.0")))) // turn a list of partly failed payment validations into a failed validation of a list of payments val failedValidationOfPayments : Validation[Error,List[Payment]] = listTraverse.sequence(successfulAndUnsuccessfulPaymentValidations)(errorValidationApplicative) val expectedFailedValidationOfPayments : Validation[Error,List[Payment]] = Failure(Error(List("PaymentAmount cannot be negative: -10.0", "CheckNumber cannot be greater than 1,000,000: 2000000", "PaymentAmount cannot be negative: -20.0", "CardNumber cannot be less than 111111: 005", "PaymentAmount cannot be negative: -30.0"))) assert( successfulAndUnsuccessfulPaymentValidations == expectedSuccessfulAndUnsuccessfulPaymentValidations) assert(failedValidationOfPayments == expectedFailedValidationOfPayments) On this slide we revisit the previous two tests but include failed validations. This showcases how the Validation Applicative for Error is able to return Validation failures informing us of all constraint violations, rather than just one (the first one). Note that since sequence is defined in terms of the map2 function of the applicative that it is being passed, the sequence function benefits from the ability of said map2 function to combine failed validations and so the end result of sequencing is a single failure whose Error informs us of all constraint violations.