[F-Lab 66해빗 페이백 챌린지 ]

[F-Lab 모각코 챌린지 3일차] 함수형 프로그래밍

everydeveloper 2023. 5. 11. 22:52

오늘의 학습 목표

  • 팀코칭에서 나는 뭐라고 답하지 답변하며 학습
  • 자바의 신 2권 chapter 20 읽기

TIL

  • 함수형 프로그래밍

 

팀코칭을 하다가 함수형 프로그래밍에 대한 개념에 대해 설명해 보라고 해서

알아보다가 정의만 보면 도저히 이해가 되지 않고

예시코드를 보긴 했는데

당장 이해가 되진 않았는데

어디서 본 듯한 꼴이였다.

 

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class FunctionalProgrammingExample {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

        // 필터링: 짝수만 걸러내기
        List<Integer> evenNumbers = numbers.stream()
                                           .filter(n -> n % 2 == 0)
                                           .collect(Collectors.toList());

        System.out.println("짝수: " + evenNumbers);

        // 매핑: 각 숫자를 제곱하기
        List<Integer> squaredNumbers = numbers.stream()
                                              .map(n -> n * n)
                                              .collect(Collectors.toList());

        System.out.println("제곱: " + squaredNumbers);

        // 리듀싱: 모든 숫자의 합 계산하기
        int sum = numbers.stream().reduce(0, Integer::sum);

        System.out.println("합계: " + sum);
    }
}

 

그래서 좀 더 알아보게 되었다.

너무 현재 메타에 맞지 않으면 검색을 하지 않을려고 했는데

다행히 요즘에도 많이 쓰이는 프로그래밍이라고 하였다.

 

 

함수형 프로그래밍의 특징

 

  • 순수 함수(Pure Functions): 순수 함수는 주어진 입력에 대해서 항상 동일한 출력을 내놓으며, 함수 외부의 상태를 변경하지 않습니다. 이로 인해 코드의 예측성이 높아지고, 테스트와 디버깅이 쉬워집니다.
  • 불변성(Immutability): 함수형 프로그래밍에서는 데이터의 상태를 변경하지 않고, 새로운 데이터를 생성하여 반환합니다. 불변성은 코드의 안정성을 높여줍니다.
  • 고차 함수(Higher-Order Functions): 함수를 인자로 받거나, 함수를 반환하는 함수를 말합니다. 고차 함수는 코드의 재사용성을 높이고, 추상화 수준을 높일 수 있습니다.
  • 커링(Currying): 다중 인자를 갖는 함수를 단일 인자를 받는 함수들의 체인으로 변환하는 기술입니다. 커링을 사용하면 코드를 더욱 간결하게 표현할 수 있습니다.
  • 지연 평가(Lazy Evaluation): 필요한 시점에만 평가가 이루어지는 방식입니다. 이를 통해 무한한 크기의 데이터 구조를 다루거나, 불필요한 계산을 최소화할 수 있습니다.

순수 함수는 무엇이고, 불변성은 또 무엇인가.....

동일한 출력을 내놓으며, 외부 상태를 변경하지 않습니다? 코드의 예측성이 높아지고, 테스트와 디버깅이 쉬워진다는데

코딩은 글로 배우는 느낌이였고, 다음에 함수형 프로그래밍 방식으로 코딩을 해보라고 하면 버벅이고 하나도 모를 것 같았다.

 

순수 함수

순수 함수 설명은 아래와 같다.

 

순수 함수(Pure Function)는 함수형 프로그래밍에서 중요한 개념으로, 다음 두 가지 조건을 만족하는 함수를 말합니다:

  1. 동일한 입력에 대해 항상 동일한 출력을 반환한다: 순수 함수는 주어진 입력에 대해서 항상 같은 결과를 반환해야 합니다. 즉, 함수의 결과는 입력값에만 의존하며, 외부 상태나 변수에 영향을 받지 않습니다.
  2. 부수 효과(side effects)가 없다: 순수 함수는 함수 외부의 어떤 상태도 변경하지 않습니다. 예를 들어, 전역 변수를 수정하거나, 인자로 전달된 객체의 속성을 변경하거나, 파일 입출력 등의 작업을 수행하는 것이 부수 효과에 해당합니다.

순수 함수의 장점은 다음과 같습니다:

  • 예측 가능성: 동일한 입력에 대해 항상 동일한 출력을 반환하므로, 함수의 결과를 쉽게 예측할 수 있습니다.
  • 테스트 용이성: 외부 상태에 의존하지 않고, 부수 효과가 없으므로, 테스트 코드를 작성하고 디버깅하기 쉽습니다.
  • 병렬 처리 가능: 순수 함수는 서로 독립적이므로, 병렬 처리를 적용하기 쉽고, 동시성 문제가 발생할 가능성이 줄어듭니다.

순수 함수의 예시는 다음과 같습니다:

public int add(int a, int b) {
    return a + b;
}

위의 add 함수는 동일한 입력값에 대해 항상 동일한 결과를 반환하며, 외부 상태를 변경하지 않으므로 순수 함수입니다. 순수 함수를 사용하면 함수형 프로그래밍의 기본 원칙에 따라 코드의 가독성과 유지 보수성을 향상시킬 수 있습니다.

 

커링

커링(Currying)은 함수형 프로그래밍에서 사용되는 기법으로, 다중 인자를 받는 함수를 단일 인자를 받는 함수들의 체인으로 변환하는 과정을 말합니다. 커링을 사용하면 함수의 부분 적용(partial application)이 가능해지고, 코드를 더 간결하고 가독성 있게 표현할 수 있습니다.

커링의 예시를 살펴보겠습니다. 두 개의 인자를 받아 더하는 함수가 있다고 가정해 보겠습니다:

function add(a, b) {
    return a + b;
}

위 함수를 커링을 사용해 단일 인자를 받는 함수들의 체인으로 변환할 수 있습니다:

function curriedAdd(a) {
    return function(b) {
        return a + b;
    }
}

이제 curriedAdd 함수는 첫 번째 인자를 받아 새로운 함수를 반환합니다. 이 반환된 함수는 두 번째 인자를 받아 최종 결과를 계산합니다. 커링된 함수를 사용하는 방법은 다음과 같습니다:

const add5 = curriedAdd(5);
const result = add5(3); // 8

 

위 예제에서 curriedAdd(5)를 호출하면 a에 5가 할당된 새로운 함수를 반환합니다. 그 다음 반환된 함수에 3을 전달하면 최종 결과인 8이 계산됩니다.

커링을 사용하면 함수의 부분 적용이 가능해져서 고차 함수(higher-order functions)를 구현하기 쉬워지고, 코드의 재사용성이 향상됩니다. 또한, 코드를 더 간결하게 표현할 수 있어 가독성이 높아집니다.

 

커링을 진행하면 자연스럽게 고차함수가 만들어진다고 한다.

 

챗GTP에게 다음과 같이 질문을 하였다.

 

커링을 진행하면 자연스럽게 고차함수로 만들어지는 거야??

 

답변이 돌아왔다.

커링(Currying)은 다중 인자를 받는 함수를 단일 인자를 받는 함수들의 체인으로 변환하는 기법입니다. 이 변환 과정에서 반환되는 각 함수는 단일 인자를 받고, 다음 인자를 받기 위해 또 다른 함수를 반환합니다. 이런 식으로 커링된 함수는 원래의 함수가 가진 모든 인자를 받을 수 있도록 만들어집니다.

이렇게 반환되는 각 함수는 모두 고차 함수(Higher-Order Function)입니다. 고차 함수는 다른 함수를 인자로 받거나 결과로 반환하는 함수를 말합니다. 커링을 통해 반환되는 각 함수는 다음 인자를 받기 위한 함수를 반환하므로, 이 함수들은 모두 고차 함수입니다.

따라서 커링을 진행하면 자연스럽게 고차 함수가 만들어집니다. 이런 고차 함수를 사용하면 코드를 더 간결하게 표현할 수 있으며, 부분 적용(Partial Application)과 같은 기법을 사용하여 더 유연하고 재사용 가능한 코드를 작성할 수 있습니다.

 

이 글만 보면 그냥 함수를 고차함수로 만드는 방법 중 하나로 소개하는 것 같긴하다.

지연평가

지연 평가(Lazy Evaluation)는 프로그래밍에서 사용되는 평가 전략 중 하나로, 표현식의 결과가 필요할 때까지 계산을 미루는 기법입니다. 이 방법은 불필요한 계산을 최소화하고, 성능을 최적화하는 데 도움이 됩니다. 지연 평가는 함수형 프로그래밍에서 자주 사용되는 전략 중 하나입니다.

지연 평가의 장점은 다음과 같습니다:

  1. 무한한 데이터 구조를 다룰 수 있다: 지연 평가를 사용하면 무한한 크기의 데이터 구조를 표현할 수 있으며, 필요한 부분만 계산하여 사용할 수 있습니다. 이는 계산 자원을 효율적으로 활용할 수 있게 해줍니다.
  2. 성능 최적화: 지연 평가를 사용하면 불필요한 계산을 피할 수 있습니다. 표현식의 결과가 실제로 필요할 때만 계산이 수행되기 때문에, 프로그램의 실행 시간이 단축될 수 있습니다.
  3. 모듈화: 지연 평가는 프로그램의 모듈화에 도움이 됩니다. 각 함수는 작은 단위로 독립적으로 작동하며, 실제로 필요한 시점에만 계산이 수행되기 때문에, 프로그램의 각 부분을 개별적으로 개발하고 테스트하기 쉽습니다.

지연 평가의 의미는 대강 이해를 하였는데

왜 객체지향에서는 지연 평가가 도입되지 않고 함수 지향 프로그래밍에서는

지연 평가가 도입이 되었을까??

먼가 알송 달송하다.

장점이 되거나 함수 지향을 하다보면 나타나는 장점 중 하나 인것 같기도 하고.

프로그래밍 기법을 만든 사람은 참 대단 한 것 같다.

 

 

아직 순수 함수, 커링, 고차함수, 지연 평가등 거의 처음 보는 단어들이 나왔고

내 기억으로는 써본적이 없는 것 같다.

객체지향이 아닌데 단순히 요즘에도 쓴다고도 하고 호기심에 공부하면서 작성하였는데

실용성이 있을까 싶기도 한데 나중에 언제가 이것도 도움이 되지는 않을까 싶기도 하고

순수히 내가 궁금해서 알아보는 거여서 시간이 많이 아깝지는 않았다.

먼저 실습이나 내가 실 코드들을 많이 접해 볼 기회가 있으면 이해가 더 잘 되었을 텐데

이론과 글로만 보니 이 건 먼가하는 개념들이 좀 있다(사실 거의 대부분이다)

객체지향과 프로그래밍도 그렇듯이 숲을 보면 좋을 것 같다.

지금은 한 나무, 한 나무 들만 봐서 아직 핵심 개념, 원리, 전체, 목적, 장점 등이 잘 보이지는 않는다.

언제나 원하는 것만 하고 살 수는 없는 것 같긴하다.

하지만

생각보다 양이 많고 계속 이어져서 오늘은 이정도로 마무리 하고 다음에 기회되면 이어서 포스팅 하도록 하겠습니다.