ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 20221030 TIL 제네릭 메서드와 Functor에 대해 알아보자
    TIL 2022. 10. 30. 15:46

     

    모나드라는 개념을 많이 들어봤는데, 잘 모르겠어서 김동경님의 naver d2의 모나드란무엇인가 영상을 보았다.

    https://www.youtube.com/watch?v=jI4aMyqvpfQ&t=726s 

    개념을 너무나 친절하고 쉽게 알려주셨는데, 제네릭이 들어간 코드로 설명을 하시는데, 제네릭이 들어간 코드를 분석할 수가 없었다. 

    그래서 제네릭에 대해 다시 한 번 정리를 해야겠다는 생각을 했다.

     

    아래의 코드는 아주 짧고, 간결한 코드인데, 제네릭 개념이 없다면 매우 혼란스럽고 도저히 해석을 할 수가 없는 코드이다.

    https://www.youtube.com/watch?v=jI4aMyqvpfQ&t=726s

     

    위의 코드를 이해하기 위해 제네릭 프로그래밍에 대해 먼저 알아보자.

    제네릭 프로그래밍은 자료형에 따라 매번 반복적으로 자료형만 다른 코드를 짜야하는 경우가 있을 때

    그렇게 짜는 것이 매우 비효율적이기 때문에 여러 자료형을 사용할 수 있도록 프로그래밍하는 방식을 말한다.

     

    컬렉션 프레임워크들은 List<E>와 같이 제네릭 프로그래밍을 활용하고 있다.

    List의 인자로 String, Integer, Long 등 많은 종류의 자료형들이 들어올 수 있는데,

    제네릭을 사용하지 않는다면 Object타입을 이용해서 어떤 타입이든 올 수 있게 만들어두고,

    원래 타입이 필요한 경우 캐스팅을 매번하는 등의 비효율적인 방법으로 많은 종류의 자료형을 처리할 수 있게 코드를 작성해야 될 것이다.

    하지만 제네릭을 사용하면 여러 자료형이 쓰일 수 있는 부분에 특정한 자료형으로 고정을 해두지 않은 채로 클래스나 메서드를 정의하고,

    사용하는 시점에 어떤 자료형을 사용할지 지정할 수 있기 때문에 형 변환 코드를 줄일 수 있다.

     

    List<E>처럼 클래스를 정의할 때 클래스 옆에 <E>와 같이 어떤 타입이든 들어올 수 있는 타입 매개변수를 표시해두고,

    타입 매개변수를 필요한 부분들에 사용하는 클래스를 제네릭 클래스라고 한다.

     

    위의 Functor는 인터페이스에 제네릭이 적용된 제네릭 인터페이스에 해당한다.

    Functor를 구현한 클래스를 사용하는 시점에 T가 String, Integer등 구체적인 타입으로 지정되고,

    map 메서드의 T에 해당 타입이 대입된다고 볼 수 있다.

     

    그런데, map 메서드 앞의 <R> Functor<R>은 무엇인가.

    보통 메서드 앞에는 메서드의 반환형이 적힌다.

    그렇다면 <R> Functor<R>이 map메서드의 반환형일까?

    그렇지 않다.

    이 코드를 해석하려면 제네릭 메서드의 형식을 알아야 한다.

     

    인터페이스, 클래스에서 제네릭을 쓸 수 있듯이, 메서드에서도 제네릭을 쓸 수 있다.

    그리고 제네릭 메서드는 꼭 제네릭 클래스에서만 쓸 수 있지 않고 일반 클래스에서도 쓸 수 있다.

    제네릭 메서드를 정의하려면 메서드에서 타입 매개변수를 이용하면 되고,

    타입 매개변수는 메서드 선언부나 메서드 매개변수에 모두 사용할 수 있다.

     

    제네릭 메서드에서 만약 사용해야 할 자료형 매개변수가 있는 경우에

    public <자료형 매개변수> 반환형 메서드 이름(자료형 매개변수 변수명,...) { ... }

    즉, public <T,...> 반환형 메서드 이름(T 변수명, ...) { ... }

    처럼 사용할 수 있는데, 메서드의 반환형 앞에 사용하는 자료형 매개변수는 메서드 내에서만 유효하다.

     

    이 코드의 map 메서드 앞의 <R> Functor<R>은 R이라는 타입 매개변수를 이 메서드에서 사용할 것이고, 

    반환형은 Functor<R>이라는 의미를 담고 있다.

    클래스에 존재하는 타입 매개변수 T 이외에도,

    Function의 result type으로 고정된 자료형이 아닌 타입 매개변수를 쓰고 싶기 때문에

    map메서드에서 R이라는 타입 매개변수를 도입해서 <R>이라고 반환형 앞에 붙여준 것이다.

    제네릭 메서드 형식을 이해함으로써 Functor코드를 읽을 수 있게 되었다!

     

    Functor는 map 메서드만 존재하는 인터페이스이고, map은 Functor<T>타입을 Functor<R>타입으로 바꿔주는 메서드이다.

    https://docs.oracle.com/javase/8/docs/api/java/util/function/Function.html

    그리고, 이 때 T와 R은 각각 map에 인자로 들어오는 함수의 input 타입과 output 타입이다.

    https://www.youtube.com/watch?v=jI4aMyqvpfQ&t=726s

    따라서 위의 map(Int stringToInt(String args))에서 인자로 받은 함수 stringToInt의

    input타입은 String이고 반환형은 Int이기 때문에,

    타입 매개변수 T는 String, R은 Int가 되어

    map은 Functor<String>을 Functor<Integer>로 바꿔주는 역할을 하게 된다고 해석할 수 있다.

     

    모나드는 Functor에 flatMap을 추가한 것이라고 영상에서 말씀해주시는데,

    사실 설명을 매우 쉽게 해주셔서 모나드에 대해서는 알게 되었지만,

    Promise나 Optional이 왜 모나드의 일종인지 아직 명확히 이해가 가지 않아서 

    이때까지는 봐도 이해가 가지 않던 매우 수학적으로 작성된 위키피디아나 다른 문서들을 조금 더 참고해서

    모나드에 대한 개념도 정리를 또 해야될 것 같다!

    댓글

Designed by Tistory.