-
Functional Effect 의 다양한 합성(composition)zio/zio-prelude 2021. 10. 10. 22:49
문제
아래와 같이 A, B, C, D 를 정의할 때, 다양하게 합성해 보자.
def A: Option[String] = { println("A") Some("A") } def B: Option[Int] = { println("B") Some(1) } def C: Option[String] = { println("C") None } def D: Option[Int] = { println("D") None }
코드
Monad 합성
val monad: Option[(String, String)] = for { c <- C a <- A } yield (a, c) println(monad) // C // None
flatMap 에 의한 순차적인 합성은 fast fail 이므로 'A' 는 출력되지 않는다.
AssociativeBoth 합성 (Applicative)
import zio.prelude._ val ap: Option[(String, String)] = (C, A).mapN { case (c, a) => (c, a) } println(ap) // C // A // None
C 가 None 이지만 이후의 A 까지 모두 실행된다. 하나라도 None 이 있으면 최종 결과는 None 이다.
위의 코드는 아래처럼 작성할 수도 있다.
import zio.prelude._ val ap: Option[(String, String)] = C <*> A println(ap) // C // A // None
Validation 합성
import zio.prelude._ def cValid: Validation[String, String] = Validation.fromOption(C).mapError(_ => "C is empty") def aValid: Validation[String, String] = Validation.fromOption(A).mapError(_ => "A is empty") val validation: Validation[String, (String, String)] = Validation.validate(cValid, aValid) println(validation) // C // A // Failure(Chunk(),NonEmptyChunk(C is empty))
AssociativeBoth 처럼 모든 항목이 실행되면서, None 이 하나라도 있을 경우 해당 에러가 NonEmptyChunk 로 누적되어 기록된다.
import zio.prelude._ def cValid: Validation[String, String] = Validation.fromOption(C).mapError(_ => "C is empty") def aValid: Validation[String, String] = Validation.fromOption(A).mapError(_ => "A is empty") def dValid: Validation[String, Int] = Validation.fromOption(D).mapError(_ => "D is empty") val validation: Validation[String, (String, String, Int)] = Validation.validate(cValid, aValid, dValid) println(validation) // C // A // D // Failure(Chunk(),NonEmptyChunk(C is empty, D is empty))
AssociativeEither 합성
import zio.prelude._ val orElse: Option[Either[String, Int]] = A <+> B println(orElse) // A // Some(Left(A))
import zio.prelude._ val orElse: Option[Either[String, String]] = C <+> A println(orElse) // C // A // Some(Right(A))
import zio.prelude._ val orElse: Option[Either[String, Int]] = C <+> D println(orElse) // C // D // None
Boolean 의 OR 연산자 처럼 왼쪽이 success 이면 오른쪽 계산은 skip 한다.
'zio > zio-prelude' 카테고리의 다른 글
ZIO prelude 의 Reader Monad (0) 2022.07.24 ZIO prelude 의 State Monad (0) 2021.09.26 NewTypes 과 Equal 을 활용한 객체 비교 (0) 2021.09.23