-
Scala State Monadscala/basic 2021. 8. 3. 12:12
문제
State Monad 를 만들고, 이를 사용해 다음을 계산하라.
골프 공을 쳐서 처음에는 20m, 두번째는 10m, 세번째는 15m 를 보냈다.
그런데 시작라인에서 3m 를 더 나온 위치에 공을 두고 쳤다면 최종 골프공은 시작라인에서 어느정도 떨어져 있을까?
3 + 20 + 10 + 15 = 48
코드
case class State[S, A](run: S => (S, A)) { def flatMap[B](f: A => State[S, B]): State[S, B] = State { s0 => val (s, a) = run(s0) // 현재 상태의 run 을 적용하고 f(a).run(s) // 이후에 f 를 적용해 S => (S, A) 함수를 갱신함 } // 기존 run 과는 다른 새롭게 정의된 S => (S, A) 함수를 이용하는 State 가 만들어짐 def map[B](f: A => B): State[S, B] = flatMap(a => State.lift(f(a))) } object State { // 초기 결과값으로 value 로 부터 State 를 만듬 // State 를 만든다는 것은 S => (S, A) 를 정의하는 것인데, A 값으로 value 사용 def lift[S, A](value: A): State[S, A] = State(s => (s, value)) } object GolfDistance { // 이동 거리를 계속 더해야 하기 때문에 state, result 를 모두 s + n 으로 def swing(n: Int): State[Int, Int] = State(s => (s + n, s + n)) def main(args: Array[String]): Unit = { val distance: State[Int, Int] = for { _ <- swing(20) _ <- swing(10) total <- swing(15) // 최종 state 와 result 에만 관심이 있다! } yield total val (s, a) = distance.run(3) // 3m 앞에서 시작해서 초기값을 3으로 해서 실행함 println(a) } }
설명
State Monad 를 직접 구현해 사용했지만, ZIO prelude 의 State Monad 에서 처럼 zio-prelude 라이브러리를 이용할 수도 있다. zio-prelude ZPure 를 사용하더라도 코드가 비슷함을 확인 할 수 있다.
그런데 java.util.concurrent._ 를 이용해 아래처럼 OOP 스타일로도 구현할 수 있지 않을까?
import java.util.concurrent.atomic.AtomicInteger object GolfDistance { case class State(s: AtomicInteger) { def swing(n: Int): Int = s.addAndGet(n) def get: Int = s.get() } def main(args: Array[String]): Unit = { val distance = State(new AtomicInteger(3)) distance.swing(20) distance.swing(10) distance.swing(15) val total = distance.get println(total) } }
위의 구현이 더 이해하기 쉬워 좋아보이는데, State Monad 로 구현했을 때 장점은 무엇인가?
그것은 아래 코드 때문인 것 같다.
def swing(n: Int): Int = s.addAndGet(n)
현재 요구 사항에 맞는 addAndGet 이 있어서 위와 같이 구현했지만, 더 복잡한 로직이 들어간다면 atomic 하게 처리할 수 있을까?
참고: https://alvinalexander.com/scala/functional-programming-simplified-book/
'scala > basic' 카테고리의 다른 글
Variance 문제 (3) 2021.10.22 apache poi 를 사용해 scala 에서 Excel 파일 읽기 (0) 2021.10.14 Pattern Match 조합 - Email 주소 예제 (0) 2021.07.27 enum 을 사용한 모델링 (0) 2021.07.23 typeclass 는 언제 사용하면 좋을까? (0) 2021.06.09