동기
- FP Monad의 기원을 찾는 자들에게 필요한 내용일 수 있다.
Signature
- Applicative는 pure와 map으로 구성되어 있다.
trait Applicative[W[_]] {
def pure[A](x: A): W[A]
def map[A, B](fa: W[A])(f: A=>B): W[B]
}
- Applicative를 활용하여 Semigroupal의 product 및 Fuctior의 map을 구현할 수 있다.
- product 함수의 구현에 있어 ap 함수가 필수적으로 필요하고 Apply Classd에 ap를 구현하여 Application이 완성되는 형태가 된다.
trait MyApply[W[_]] extends Functor[W] with Semigroupal[W] {
override def product[A, B](fa: W[A], fb: W[B]): W[(A, B)] = {
val fuctionWrapper: W[B => (A, B)] = map(fa)(a => (b: B) => (a, b))
ap(fuctionWrapper)(fb)
}
def ap[W[_], B, T](wf: W[B=>T])(wa: W[B]): W[T]
}
- Application으로 Semigroupal.product을 구현할 수 있다.
- Apply의 ap 함수가 없으면 구현이 불가능하다.
def productWithApplicatives[W[_], A, B](wa: W[A], wb: W[B])(implicit applicative: Applicative[W]): W[(A, B)] = {
val fuctionWrapper: W[B => (A, B)] = applicative.map(wa)(a => (b: B) => (a, b))
applicative.ap(fuctionWrapper)(wb)
}
활용 (Appicatives)
- Applicative 의 pure함수를 활용하면 아래와 같이 Wrapper[Type] 형태의 데이터를 쉽게 생성할 수 있다.
- map 함수를 활용하여 내부 데이터의 변환도 용이하다.
- 아래 Validated.valid(22)와 같이 다양한 이름으로 pure 함수가 제공된다.
import cats.Applicative
import cats.instances.list._
val listApplicative = Applicative[List]
val aList = listApplicative.pure(2) // List(2)
import cats.instances.option._
val optionApplicative = Applicative[Option]
val anOption = optionApplicative.pure(2) // Some(2)
// pure extension method
import cats.syntax.applicative._
val aSweetList = 2.pure[List]
val aSweetOption = 2.pure[Option]
// Monads extends Applicatives
// Applicatives extends Functors
import cats.data.Validated
type ErrorOr[T] = Validated[List[String], T]
val aValidValue = Validated.valid(22) // pure
val aModifiedValidate: ErrorOr[Int] = aValidValue.map(_ + 1) // map
Apply
- Cats에서는 Apply에 product와 ap 함수를 정의하고 있다.
trait MyApply[W[_]] extends Functor[W] with Semigroupal[W] {
override def product[A, B](fa: W[A], fb: W[B]): W[(A, B)] = {
val fuctionWrapper: W[B => (A, B)] = map(fa)(a => (b: B) => (a, b))
ap(fuctionWrapper)(fb)
}
def ap[W[_], B, T](wf: W[B=>T])(wa: W[B]): W[T]
}
활용(Apply)
- Wrapping된 Data에 정의한 함수로 조작이 가능하다.
- 여러 데이터의 동시 조작을 위해 mapN형태의 함수를 제공한다.
import cats.Apply
import cats.instances.option._
val applyOption = Apply[Option]
val funcApp = applyOption.ap(Some((x:Int) => x + 1))(Some(2)) // Some(3)
import cats.syntax.apply._
val tupleOfOptions = (Option(1), Option(2), Option(3))
val optionOfTuples = tupleOfOptions.tupled
val sumOption = tupleOfOptions.mapN(_ + _ + _)
정리
- 아래와 같이 Monad는 여러 특성을 상속받는다.
- trait Monad extends Applicative with Apply with Semigroupal with Functor
---
[Functor][Semigroupal]
⇡⇡
[Apply]
⇡
[Applicative]
⇡
[Monad]
'Tech > Scala' 카테고리의 다른 글
Functional Effect 정리 (1) | 2024.09.01 |
---|---|
함수형 프로그래밍 Type Class : FlatMap and Monad (0) | 2024.02.24 |
함수형 프로그래밍 Type Class : Semigroupal (1) | 2024.02.14 |
함수형 프로그래밍의 시작점(?), Free Monad in Scala (0) | 2023.10.13 |
함수형 프로그래밍의 Monad 개념 정리 (in Scala) (0) | 2022.12.20 |