[Computer Science] 함수형 프로그래밍

in·2023년 10월 7일
0

Computer Science

목록 보기
6/6

📌 함수형 프로그래밍

순수 함수를 조합하고 공유 상태, 변경 가능한 데이터 및 부작용을 피해 소프트웨어를 만드는 프로세스
(기존의 사고방식을 전환하여 프로그래밍을 더 유연하게 문제해결 하도록 접근하는 것)

  • 선언형 프로그래밍으로 애플리케이션의 상태는 순수 함수를 통해 전달
  • 애플리케이션의 상태가 일반적으로 공유되고 객체의 메소드와 함께 배치되는 OOP와는 대조되는 프로그래밍 방식

명령형 프로그래밍

상태와 상태를 변경시키는 관점에서 연산을 설명하는 방식
알고리즘을 명시하고, 목표는 명시하지 않음

  • 절차지향 프로그래밍 : 수행되어야 할 순차적인 처리 과정을 포함하는 방식(C, C++)
  • 객체지향 프로그래밍 : 객체들의 집합으로 프로그램의 상호작용을 표현(C++, Java, C#)

선언형 프로그래밍

How보다는 What을 설명하는 방식(어떻게보단 무엇을)
알고리즘을 명시하지 않고 목표만 명시함

  • 함수형 프로그래밍 : 순수 함수를 조합하고 소프트웨어를 만드는 방식(클로저, 하스켈, 리스프)

➡️ 명령형 프로그래밍은 어떻게 할지 표현하고 선언형 프로그래밍을 무엇을 할건지 표현한다.

함수형 프로그래밍의 의미를 파악하기 전 꼭 알아야 할 것들

  • 순수 함수(Pure functions)
    : 부수 효과들을 제거한 함수(Memory or I/O의 관점에서 Side Effect가 없는 함수, 함수의 실행이 외부에 영향을 끼치지 않는 함수)

    • 함수 자체가 독립적이며 Side Effect가 없기 때문에 Thread에 안전성을 보장받을 수 있다.
    • Thread의 안전성을 보장받아 병렬 처리를 동기화 없이 진행할 수 있다.

    ➕ 부수 효과(Side Effect)

    • 변수의 값 변경
    • 자료 구조를 제자리에서 수정
    • 객체의 필드값 설정
    • 예외나 오류가 발생하며 실행 중단
    • 콘솔 또는 파일 I/O가 발생
  • 합성 함수 (Function composition)

  • 공유상태 피하기(Avoid shared state)

  • 상태변화 피하기(Avoid mutating state)

  • 부작용 피하기(Avoid side effects)
    프로그래머가 바꾸고자 하는 변수 외에는 변경되면 안됨(원본 데이터는 불변)

예시

순수함수

// arr 넣어서 map 얻기

var arr = [1, 2, 3, 4, 5];
var map = arr.map(function(x) {
  return x * 2;
}); // [2, 4, 6, 8, 10]

➡️ arr를 사용했지만 값은 변하지 않았고 map이라는 결과를 내고 부작용을 낳지 않음

순수함수X

var arr = [1, 2, 3, 4, 5];
var condition = function(x) { return x % 2 === 0; }
var ex = function(array) {
  return array.filter(condition);
};
ex(arr); // [2, 4]

➡️ ex 메소드에서 인자가 아닌 condition을 사용했기 때문

var ex = function(array, cond) {
  return array.filter(cond);
};
ex(arr, condition);

➡️ 순수함수로 만들면 에러를 추적하는 것이 쉬워짐(인자 혹은 함수 내부의 문제 둘 중 하나)

📌 Java에서의 함수형 프로그래밍

  • 최대한 순수함수를 지향하고 숨겨진 입출력을 최대한 제거하여 코드를 순수한 입출력 관계로 사용하는 것이 함수형 프로그래밍의 목적

Java에서 활용할 수 있는 함수형 프로그래밍

  • 람다식
  • stream API
  • 함수형 인터페이스

Java 8에 추가된 Stream API

import java.util.Arrays;
import java.util.List;

public class stream {

	public static void main(String[] args) {
		List<String> myList = Arrays.asList("a", "b", "c", "d", "e");
 
        // 기존방식
        for(int i=0; i<myList.size(); i++){
            String s = myList.get(i);
            if(s.startsWith("c")){
                System.out.println(s.toUpperCase());
            }
        }
 
        // stream API를 이용한 방식
        myList.stream()
              .filter(s -> s.startsWith("c"))
              .map(String::toUpperCase)
              .forEach(System.out::println);
 
	}

}

[참고 자료]

🔗링크
🔗링크

0개의 댓글