분류 javascript

함수형 프로그래밍이란 무엇입니까?

컨텐츠 정보

  • 조회 287 (작성일 )

본문

프로그래머는 아마도 우아하고 유지 관리 가능하고 확장 가능하며 예측 가능한 코드를 작성하려고 할 것입니다. 

함수 프로그래밍 (FP)의 원칙은 이러한 목표를 크게 지원할 수 있습니다.


https://www.sitepoint.com/what-is-functional-programming/ 


함수형 프로그래밍은 불변성, 일류 함수, 참조 투명성 및 순수한 함수를 중시하는 패러다임 또는 스타일입니다. 그 말들 중 어느 것도 당신에게 의미가 없다면 걱정하지 마십시오! 이 기사에서는 이 모든 용어를 세분화 할 것입니다.


함수형 프로그래밍은 함수 추상화와 일반화를 중심으로 구축 된 수학적 시스템인 람다 미적분에서 진화했습니다. 결과적으로 많은 함수형 프로그래밍 언어가 매우 수학적으로 보입니다. 좋은 소식,하지만 : 당신은 당신의 코드에 함수형 프로그래밍 원칙을 가지고 함수형 프로그래밍 언어를 사용할 필요가 없습니다. 이 글에서는 JavaScript를 사용합니다. JavaScript는 패러다임에 묶이지 않고 함수형 프로그래밍에 적합하도록 하는 많은 기능을 가지고 있습니다.


함수형 프로그래밍의 핵심 원칙 


함수형 프로그래밍이 무엇인지 살펴 보았으므로 FP의 핵심 원칙에 대해 이야기하겠습니다.


순수한 함수 


함수를 기계라고 생각합니다. 입력 또는 인수를 취한 다음 반환 값을 출력합니다. 순수 함수에는 '부작용'이나 기능의 출력과 관련이 없는 동작이 없습니다. 일부 잠재적 부작용은 값을 인쇄하거나 console.log를 사용하여 로그 아웃하거나 함수 외부의 변수를 조작하는 것입니다.


불순 함수의 예는 다음과 같습니다.


let number = 2;

function squareNumber() {
  number = number * number; // impure action: manipulating variable outside function
  console.log(number); // impure action: console log-ing values
  return number;
}

squareNumber();

아래 함수는 순수합니다. 입력을 받아서 출력을 생성합니다.


// pure function
function squareNumber(number) {
  return number * number;
}

squareNumber(2);

순수한 함수는 함수 외부의 상태와 독립적으로 작동하므로 전역 상태나 외부 변수에 의존해서는 안됩니다. 첫 번째 예에서는 함수 외부에서 만든 숫자 변수를 사용하여 내부에 설정합니다. 이것은 원칙을 위반합니다. 끊임없이 변화하는 전역 변수에 크게 의존하는 경우 코드를 예측할 수 없고 추적하기가 어렵습니다. 버그가 발생하는 위치와 값이 변경되는 이유를 파악하기가 더 어려울 것입니다. 대신 함수의 로컬 입력, 출력 및 변수만 사용하면 디버깅이 더 쉬워집니다.


또한 함수는 참조 투명도를 따라야 합니다. 즉, 특정 입력에서 출력이 항상 동일하다는 것을 의미합니다. 위 함수에서 2를 함수에 전달하면 항상 4를 반환합니다. 두 가지 예와 같이 API 호출 또는 난수 생성에 대해서도 마찬가지입니다. 동일한 입력이 주어지면 출력이 반환되거나 반환 되지 않을 수 있습니다.


// Not referentially transparent
Math.random();
// 0.1406399143589343
Math.random();
// 0.26768924082159495ß

불변성 


함수형 프로그래밍은 또한 불변성을 우선시하거나 데이터를 직접 수정하지 않습니다. 불변성은 예측 가능성으로 이어집니다. 데이터의 가치를 알고 있으며 변하지 않습니다. 코드를 단순하고 테스트 가능하며 분산 및 다중 스레드 시스템에서 실행할 수 있습니다.


데이터 구조로 작업 할 때 불변성이 자주 발생합니다. JavaScript의 많은 배열 메소드는 배열을 직접 수정합니다. 예를 들어 .pop()은 배열의 끝에서 항목을 직접 제거하고 .splice()를 사용하면 배열의 섹션을 가져올 수 있습니다. 대신 함수형 패러다임 내에서 배열을 복사하고 해당 프로세스에서 제거하려는 요소를 제거합니다.


// We are mutating myArr directly
const myArr = [1, 2, 3];
myArr.pop();
// [1, 2]
// We are copying the array without the last element and storing it to a variable
let myArr = [1, 2, 3];
let myNewArr = myArr.slice(0, 2);
// [1, 2]
console.log(myArr);

일류 함수 (First-class functions) 


함수형 프로그래밍에서 함수는 일류이므로 다른 값처럼 사용할 수 있습니다. 함수 배열을 만들어 다른 함수에 인수로 전달하고 변수에 저장할 수 있습니다.


let myFunctionArr = [() => 1 + 2, () => console.log("hi"), x => 3 * x];
myFunctionArr[2](2); // 6

const myFunction = anotherFunction => anotherFunction(20);
const secondFunction = x => x * 10;
myFunction(secondFunction); // 200

고차 함수 (Higher-order functions) 


고차 함수는 두 가지 중 하나를 수행하는 함수입니다. 함수를 하나 이상의 매개 변수로 사용하거나 함수를 반환합니다. 배열과 상호 작용하는 데 사용할 수 있는 map, reduce 및 filter와 같이 JavaScript에 내장 된 첫 번째 유형의 고차 함수 유형이 많이 있습니다.


filter는 우리가 제공하는 조건에 맞는 값만 포함하는 이전 배열에서 새 배열을 반환하는 데 사용됩니다.


const myArr = [1, 2, 3, 4, 5];

const evens = myArr.filter(x => x % 2 === 0); // [2, 4]

map은 제공된 논리에 따라 각 항목을 수정하여 배열의 항목을 반복하는 데 사용됩니다. 아래 예제에서는 값에 2를 곱하는 맵에 함수를 전달하여 배열의 각 항목을 두 배로 늘립니다.


const myArr = [1, 2, 3, 4, 5];

const doubled = myArr.map(i => i * 2); // [2, 4, 6, 8, 10]

reduce는 입력 된 배열을 기반으로 단일 값을 출력 할 수 있게 합니다. 배열, 평면 배열 또는 그룹 값을 어떤 방식으로 합산하는 데 자주 사용됩니다.


const myArr = [1, 2, 3, 4, 5];

const sum = myArr.reduce((i, runningSum) => i + runningSum); // 15

당신은 또한 그들 자신을 구현할 수 있습니다! 예를 들어 다음과 같이 필터 함수를 만들 수 있습니다.


const filter = (arr, condition) => {
  const filteredArr = [];

  for (let i = 0; i < arr.length; i++) {
    if (condition(arr[i])) {
      filteredArr.push(arr[i]);
    }
  }

  return filteredArr;
};

두 번째 유형의 고차 함수 인 다른 함수를 반환하는 함수도 비교적 빈번한 패턴입니다. 예를 들면 다음과 같습니다.


const createGreeting = greeting => person => `${greeting} ${person}`

const sayHi = createGreeting("Hi")
console.log(sayHi("Ali")) // "Hi Ali"

const sayHello = createGreeting("Hello")
console.log(sayHi("Ali")) // "Hello Ali"

Currying는 당신이 읽는 데 관심이 있을 수 있는 관련 기술입니다!


함수 구성 


함수 구성은 더 복잡한 함수를 만들기 위해 여러 간단한 함수를 결합하는 것입니다. 따라서 평균 함수와 배열 값을 합산하는 합 함수를 결합하는 averageArray 함수를 사용할 수 있습니다. 개별 기능은 작으며 다른 목적으로 재사용 할 수 있으며,보다 완전한 작업을 수행 할 수 있습니다.


const sum = arr => arr.reduce((i, runningSum) => i + runningSum);
const average = (sum, count) => sum / count;
const averageArr = arr => average(sum(arr), arr.length);

혜택 


함수형 프로그래밍은 모듈 식 코드로 이어집니다. 반복해서 재사용 할 수 있는 작은 기능이 있습니다. 각 함수의 특정 기능을 알면 버그를 정확히 찾아 내고 테스트를 작성하는 것이 간단해야 합니다. 특히 함수 출력을 예측할 수 있어야 하기 때문입니다.


또한 여러 코어를 사용하려는 경우 해당 코어에 함수 호출을 분산하여 계산 효율성을 높일 수 있습니다.


함수형 프로그래밍을 어떻게 사용할 수 있습니까? 


이러한 모든 아이디어를 통합하기 위해 함수형 프로그래밍으로 완전히 넘어갈 필요는 없습니다. 많은 아이디어를 객체 지향 프로그래밍과 함께 잘 사용할 수도 있는데, 이는 종종 상대방으로 간주됩니다.


예를 들어, React는 불변 상태와 같은 많은 함수형 주체를 통합하지만 주로 수년간 클래스 구문을 사용했습니다. 또한 거의 모든 프로그래밍 언어로 구현할 수 있습니다. 실제로 원하지 않는 한 Clojure 또는 Haskell을 작성할 필요가 없습니다.


함수형 프로그래밍 원칙은 순수하지 않더라도 코드에서 긍정적인 결과를 가져올 수 있습니다.