프로그래밍 패러다임 - 선언형 프로그래밍과 함수형 프로그래밍

차선호·2023년 8월 21일
0

Programming Paradigm

목록 보기
1/1
post-thumbnail

선언형 프로그래밍


선언형 프로그래밍이란


선언형 프로그래밍은 어떤 방법(How)으로 동작하는지 나타내기 보다 무엇(What)을 하는지를 중점으로 하는 방법이다.

//코드1(명령형)
function addOne (arr) {
    let results = [];
    for(let i=0; i<arr.length; i+=1){
        results.push(arr[i]+1);
    }
    return results;
}

먼저 코드 1을 보면,

addOne이라는 함수는 arr 배열을 파라미터로 받고 나서 result라는 새로운 배열을 선언한 뒤, 배열 arr의 원소들에 1을 더 해서 result 배열에 push한 다음 그 값을 리턴하는 함수이다.

이렇게 어떻게(How) 동작하는지 확실하게 알 수 있다. 근데 그러면 당연히 이렇게 하지 선언형은 어떤 걸 말하는거지? 궁금점이 생길 것이다.

//코드2(선언형)
function addOne (arr) {
    return arr.map((i) => i+1);
}

코드 2를 보면,

단순히 javaScript의 내장형 함수로 바꿔 쓴게 선언형 프로그래밍이라고 생각이 들 수 있다.

하지만 여기서 중요한 건 내장형 함수로 바꾸면서 추사화가 되었다는 것이다.

즉, 선언형 프로그래밍에서 가장 중요한 점은 명령형 프로그래밍의 추상화라는 것이다.

위 코드를 보면 결국 어떤(What) 일이 일어나는지를 보여주지 어떻게(How) 원하는 결과를 만들어내느지는 중요하지 않다.

선언형 프로그래밍의 분류


함수형 언어

  • 수학적 함수를 조합하여 문제를 해결하는 언어

    • 알려진 값을 함수에 적용하는 것을 기반으로 한다.
  • side effect가 발생하지 않도록 함수를 짜야 한다.

    • side effect : 함수의 실행 결과가 함수 밖의 상항에 영향을 끼치거나, 함수 밖의 상황이 함수의 실행결과에 영향을 미치는 것
    • side effect가 없으려면 입력받은 파라미터 외의 전역변수 등을 참조하지 않아야 하며 수정해서도 안된다. 또, return 값이 있어야 하며 함수를 이용하는 이유는 오직 이 return 값을 받기 위해서이다.
  • 재귀 호출이 자주 이용된다.

  • 병렬 처리에 유리하다.

  • 종류 : LISP


논리형 언어

  • 기호 논리학에 기반을 둔 언어로, 논리 문장을 이용하여 프로그램을 표현하고 계산한다.

  • 반복문이나 선택문을 사용하지 않는다.

  • 비절차적 언어이다.

  • 종류 : PROLOG


선언형 프로그래밍 종류


HTML
  • 웹 브라우저의 표준 문서인 하이퍼텍스트 문서를 만들기 위해 사용하는 언어

  • 특별한 데이터 타입이 없고 변수 사용이 없다.

  • 호환성이 좋고 사용이 편리하다.

LIS

  • 함수형 프로그래밍 언어, 수학 표기법을 나타내기 위한 목적
  • 특이하게 전위 표기법을 사용
  • 인공지능 분야에 사용되는 언어

PROLOG

  • 대표적인 논리형 언어로, Object(객체)간의 Relation을 표기하는 데 집중하는 언어
  • 인공지능 분야에서 논리적인 추론이라 리스트 처리에 사용된다.

XML

  • 기존 HTML의 단점을 보완하여 웹에서 구조화된 다양한 문서들을 상호 교환할 수 있도록 설계된 언어
  • HTML에 사용자가 새로운 태그를 정의할 수 있고, 이를 표현하는 방식이 독립적이다.

HASKELL

  • 함수형 프로그래밍 언어의 한 종류로, 코드가 간결하고 에러가 날 확률이 낮다.

SQL

  • 관계형 데이터베이스 관리 시스템의 데이터를 관리하기 위해 설계된 특수 목적의 프로그래밍 언어

선언형 프로그래밍의 장점

가독성과 재사용성이 좋고, 작동 순서를 구체적으로 작성하지 않아서 오류가 적다.

프로그램 동작을 변경하지 않고도 관련 값을 대체할 수 있다.

해당 언어에서 문제가 발생해도 다른 것에 영향을 주지 않는다.(참조 투명성)


함수형 프로그래밍


함수형 프로그래밍이란


함수형 프로그래밍은 선언형 프로그래밍의 일종으로 프로그램이 상태의 변화 없이 데이터 처리를 수학적 함수 계산으로 취급하고자 하는 패러다임이다.

순수 함수의 조합으로 프로그래밍하며 최종 Output이 발생할 수 있도록 순수 함수들을 엮어서 호출한다. 문이 아닌 식이나 선언으로 수행되는 선언형 프로그래밍 패러다임을 따르고 있다.

함수형 프로그래밍의 특징


순수 함수

  • 동일한 입력에는 항상 같은 값을 반환한다.

  • 함수의 출력(return)은 오로지 그 함수에 입력된 값(input)에만 의존한다.

  • 함수의 실행은 프로그램의 실행에 영향을 미치지 않아야 한다.Self-contained되어야 한다. 즉, side effect가 없다.Side effect가 없다는 의미는 오로지 출력(return) 만 수행한다는 의미이다.

불변성

  • Input의 Immutability을 유지해야 순수함수의 순수성 유지가 의미가 있다.

  • 구조체를 Input에 넣었을 때와 클래스를 Input에 넣었을 때 불변성을 유지시키는 구조가 다르다. 구조체는 deep copy이기 때문에 함수 내에서 변경이 불가능하기 때문에 Input의 불변성을 고민하지 않아도 된다. 하지만 클래스는 swallow copy이기 때문에 함수 내에서 속성 변경이 가능하다. 이는 함수가 상태를 변경할 수 있는 여지를 주게 되므로 주의해야 한다.

참조의 투명성

  • 함수의 순수성, 전달인자의 불변성을 유지하면 다음과 같은 참조의 투명성을 기대할 수 있다.

    • 자기 충족적이다(self-contained). 함수 외부에 의존하는 코드가 없고, 함수 사용자 입장에서는 유효한 매개변수만 전달하면 된다.

    • 결정론적이다 (deterministic). 동일한 매개변수에 대해서는 항상 동일한 결과가 나온다.

    • 예외 (Exception) 를 던지지 않는다. out of memory error 혹은 stack overflow error 는 발생할 수 있지만, 이러한 에러들은 버그로 취급되며, 함수의 사용자가 다룰 수 있는 것은 아니다.

    • 다른 코드가 예기치 않게 실패하는 조건을 만들지 않는다. 예를 들어, 참조 투명성을 가진 함수는 매개 변수의 값을 변경하거나 함수 외부의 데이터를 변경하지 않는다.

    • 데이터베이스, 파일 시스템, 네트워크 등의 외부 기기로 인해 동작이 멈추지 (hang) 않는다.

Avoid

  • 함수형 프로그래밍에서 가장 피해야 하는 지점이다.

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

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

    • 부작용 피하기 (Avoid side effects)


함수형 프로그래밍의 활용


함수의 합성

  • 원하는 Output을 위해 둘 이상의 재사용 가능한 순수 함수를 조합하는 과정을 말한다.

  • 함수형 프로그램은 여러 작은 순수 함수들로 이루어져있기 때문에 이 함수들을 연쇄적으로 또는 병렬로 호출해서 더 큰 함수를 만드는 과정으로 전체 프로그램을 구축한다. 그리고 이 과정에서 함수를 엮기 때문에 고차원함수(Higher-Order Functions)를 활용해야 한다.

    • 고차원 함수는 함수를 인자로 받고 또 결과로 반환하는 함수를 이야기한다.
  • 이 때문에 함수형 프로그래밍에서 함수는 일급객체여야 한다.

    • 일급객체
      • 전달인자(argument)로 전달할 수 있다.
      • 동적 프로퍼티 할당이 가능하다. 컴파일 단계가 아니라 런타임시에도 할당이 가능하다는 뜻이다.
      • 변수나 데이터 구조(자료구조) 안에 담을 수 있다
      • 반환 값으로 사용할 수 있다.
      • 할당할 때 사용된 이름과 관계없이 고유한 객체로 구별할 수 있다.
  • swift에서는 filter, map, flatMap, reduce 등의 기능을 사용할 수 있다.

Function Decoration

  • 순수함수를 재사용하다보면, 이미 만들어진 순수함수를 그대로 적용하기보다 일부 개선하거나, 조금 다른 방향으로 수정해야 하는 상황이 발생할 수 있다. 이 때 function decoration을 적용한다.

Partial Application & Curring

  • 순수 함수를 조합하다보면, 인자의 수가 서로 맞지 않는 순수함수를 엮어야 하는 상황이 있을 수 있다. 이 상황을 Arity(the number of arguments taken by a function) Mismatch라 한다.
  • Arity Mismatch는 왜 일어날까? 순수함수 중에는 2개 이상의 인자를 필요로 하는 함수가 있을 수 있음 이 순수함수는 2개 이상의 순수함수에서 실행된 출력값을 받아와야 함 하지만 함수는 무조건 1개의 return 값만 나옴 이렇게 인자의 수가 서로 맞지 않는 상황을 Arity Mismatch라 한다.
  • Partial Application & Curring으로 Arity Mismatch을 해결 Partial Application : 인자를 부분적으로 먼저 엮어준다. Curring : 인자를 하나씩만 받는 함수의 체인으로 만드는 방법이다.
// Partial Application
func add(_ a: Int, _ b: Int) -> (Int) -> Int {
    return { c in
        return a + b + c
    }
}
var addTenFive = add(10, 5)//10과 5를 미리 합쳐준다!
print(addTenFive(5)) // 미리 10과 5가 합쳐줬기 때문에 20이 나온다.

//Curring
func before(_ a: String) -> ((String)->String) {
  return { b in
      return a + b;
  }
}
var word = before("이렇게");
var finalWord = word("붙어요!");
print(finalWord); //이렇게붙어요!

함수형 프로그래밍의 장점

  1. 여러 가지 연산 처리 작업이 동시에 일어나는 프로그램을 만들기 쉽다.
  2. 멀티 코어 혹은 여러 개 연산 프로세서를 사용하는 시스템에서 효율적인 프로그램을 만들기 쉽다.
  3. 상태변화에 따른 부작용에서 자유로워지기 때문에 순수하게 기능 구현에 초점을 맞추어 설계할 수 있다.

함수형 프로그래밍의 단점

  1. 순수함수를 구현하기 위해 코드의 가독성이 좋지 않을 수 있다.
  2. 재귀적 코드 스타일은 무한루프에 빠질 수 있다.
  3. 순수함수를 쓰는건 쉬울 수 있지만, 그것들을 조합하는 것은 쉽지 않다.
profile
dkssud!

0개의 댓글