콘텐츠로 이동

2023 11 19

2023-11-19

Functor, Monad

참고: https://tech.kakao.com/2017/09/02/parallel-programming-and-applicative-in-scala/ 참고: https://gist.github.com/jooyunghan/e14f426839454063d98454581b204452

  • Functor
    • A => B 함수를 받아 F[A] => F[B] 로 변형시키는 것
    • map 떠올리면 됨
      val list = List(1, 2, 3, 4, 5)
      val double = (a: Int) => a * 2
      val doubleList = list.map(e => double(e))
      println(doubleList) // List(2, 4, 6, 8, 10)
      
  • Monad
    • A => F[B] 함수를 받아 F[A] => F[B] 로 변형시키는 것
    • flatMap 떠올리면 됨
      val list = List(1, 2, 3)
      val makeSizeTwoList = (a: Int) => List(a, a)
      val twoList = list.flatMap(e => makeSizeTwoList(e))
      println(twoList) // List(1, 1, 2, 2, 3, 3)
      

flatMap으로 살펴보는 monad 합성의 용이함

def future(a: Int) => Future {
  Thread.sleep(1000)
  a
}

val listFuture: List[Future[Int]] = List(future(10), future(20), future(30))
val futureList: Future[List[Int]] = Future.sequence(listFuture)
futureList.map {ints => println(ints)}

// flatMap을 사용하여 List[Future[Int]] => Future[List[Int]] 로 바꿔보자
val transform1: List[Future[Int]] =
  listFuture(0).flatMap(a => {
    listFuture(1).flatMap(b => {
      listFuture(2).map(c => {
        List(a, b, c)
      }
    })
  })

// 조금 더 정형화 시키면
def transform2(listFuture: List[Future[Int]], acc: List[Int] = Nil): Future[List[Int]] = {
  listFuture match {
    case Nil => Future.successful(acc.reverse)
    case head :: tail => head.flatMap(e => transform2(tail, e :: acc))
  }
}

Future.successful()

import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global

object ScalaTest extends App {
  def future(a: Int) = {
    Future.successful {
      Thread.sleep(1000)
      println(a)
      a
    }
  }

  val listFuture: List[Future[Int]] = List(future(10), future(20), future(30))
  val futureList: Future[List[Int]] = Future.sequence(listFuture)
  futureList.map { ints =>
    println(ints)
  }
}
  • 해당 코드에서 10, 20, 30이 순차적으로 1초 간격으로 프린트되는 현상 발견
  • Future.successful()은 Future 가 이미 연산이 완료되었다는 뜻
    • Thread.sleep(1000), println(a)가 즉시 future 함수가 호출될 때 수행되고, 이거는 async한 연산이 아니야
      import scala.concurrent.Future
      import scala.concurrent.ExecutionContext.Implicits.global
      
      object ScalaTest extends App {
        def future(a: Int) = {
          Future {
            Thread.sleep(1000)
            println(a)
            a
          }
        }
      
        val listFuture: List[Future[Int]] = List(future(10), future(20), future(30))
        val futureList: Future[List[Int]] = Future.sequence(listFuture)
        futureList.map { ints =>
          println(ints)
        }
      }