동기

  • 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]

 

+ Recent posts