본문 바로가기
Computer Science

Scala에서 Continuation Monad를 구현해 보았다

by invrtd.h 2023. 9. 8.

일단 Continuation Monad에 대해 되게 잘 설명한 글을 찾았는데

 

https://gall.dcinside.com/mgallery/board/view/?id=github&no=35622&search_pos=-38670&s_type=search_subject_memo&s_keyword=continu&page=1 

 

이거다

그리고 내가 왜 Continuation Monad를 구현하고 앉아 있냐...하면 KAIST의 프로그래밍 언어론(CS320)을 독학하고 있었는데 거기서 Continuation Passing Style이 나오고, 처음 봤을 땐 잘 이해가 안 돼서 포기하고 있었다. 근데 이젠 어느 정도 이해함

 

바로 코드를 보자

 

private class Cont[R, U](data: (U => R) => R) {
  def applyCont(f: U => R): R = data(f)

  def map[U2](fn: U => U2): Cont[R, U2] = Cont(
    (f: U2 => R) => applyCont(fn.andThen(f))
  )

  def flatMap[U2](fn: U => Cont[R, U2]): Cont[R, U2] = Cont(
    (f: U2 => R) => applyCont(u => fn(u).applyCont(f))
  )
}

def toCont[R, U](u: U): Cont[R, U] = Cont((f: U => R) => f(u))

def addCPS(a: Int, b: Int): Cont[Int, Int] = toCont(a + b)
def subCPS(a: Int, b: Int): Cont[Int, Int] = toCont(a - b)
def mulCPS(a: Int, b: Int): Cont[Int, Int] = toCont(a * b)

@main
def main(): Unit = {
  val ret = for {
    v1 <- addCPS(1, 2)
    v2 <- subCPS(7, 4)
    v3 <- mulCPS(v1, v2)
  } yield v3
  println(ret.applyCont(x => x))
}

 위 링크 달아둔 글을 거의 그대로 구현했다.

 먼저 Cont[R, U] 타입은 (U => R) => R 타입을 의미함

 일반 함수를 f: T => U라고 하고, continuation을 U => R이라고 하면, Cont[R, U] 타입은 continuation 하나를 받아서 그 continuation의 리턴값을 리턴하는 함수겠죠

 즉 continuation이 cont: U => R이라고 하면 Cont[R, U] 타입은 cont 함수의 인자가 될 u를 미리 들고 있습니다 그리고 임의의 continuation인 cont가 인자로 들어오면 cont(u)를 계산해서 리턴합니다

 

 이제 모나딕함을 구현하기 위해 map 함수와 flatMap 함수만 구현해주면 되는데요

 map은 쉽습니다 임의의 f: U => U2 함수를 Cont[R, U] => Cont[R, U2] 함수로 바꿔 주기만 하면 되죠

 근데 Cont[R, U] 타입이 cont 함수의 인자가 될 u를 미리 들고 있다고 했으므로 Cont[R, U2] 타입은 f(u)를 들고 있으면 될 것 같음

 

 flatMap은 임의의 f: U => Cont[R, U2] 함수를 Cont[R, U] => Cont[R, U2] 함수로 바꿔 주면 되겠죠

 map을 먼저 한 뒤에 unit을 해 주는 방식으로 처리합시다

 모든 Cont[R, X] 타입은 X 타입으로 생각해줄 수 있겠죠 왜냐하면 내부에 x를 들고 있으므로

댓글