티스토리 뷰

함수형 프로그래밍이란?

  • 함수형 프로그래밍(functional programming)은 자료 처리를 수학적 함수의 계산으로 취급하고 상태와 가변 데이터를 멀리하는 프로그래밍 패러다임의 하나.
  • 상태, 가변 데이터를 지양.
  • 상태의 변경이 아닌 함수의 응용을 통해 프로그래밍.
  • 절차의 기술이 아닌 선언적으로 기술되는 선언형 프로그래밍 패러다임을 따름.
  • 아래의 내용으로 보통 정의내림
    • FP is about pulling programs apart and reassembling them from the same parts, composing in functions together and that means we need to make the output of a function to serve as the input of the next one, in order to do so, we should avoid shared mutable state & side-effects (use pure functions)

 함수형 프로그래밍의 역사

  • 알론조 처치가 1930년대에 개발한 람다 대수에서 함수에 대한 이론적 기반 태동.
  • 1930년대에 계산가능성, 결정문제, 함수정의, 함수응용과 재귀를 연구하기 위해 람다 대수를 이용.
  • 최초 함수형 프로그래밍 언어 IPL을 개발.
  • 이후 훨씬 향상된 함수형 프로그래밍 언어인 리스프가 개발됨.
    •  리스프는 현대적 함수형 프로그래밍의 여러 특징을 가짐
  • 1980년대에 그동안의 함수형 프로그래밍에 대한 연구를 바탕으로 순수 함수형 언어인 하스켈 탄생.
  • 최근 2000년대부터 cpu의 단일 코어 처리 한계가 찾아오고 멀티 코어 체제로 전환되면서 함수형 프로그래밍이 가진 특징을 적용해보고자 하는 수요가 증가.

 함수형 프로그래밍 특징

  • 함수는 절차에 집중하지 않고 결과에 집중.
  • 무엇이 계산될지에만 강점을 둠.
  • 데이터는 불변형.
  • 문제를 여러 함수들로 분해하여 다룸.
  • 계산을 위해 재귀와 조건절을 사용하는 수학 함수 개념에 기초.
  • 루프 문과 같은 반복문과 조건문은 지원하지 않음. → if else가 있어 혼동될 수 있으나 함수형에서 이는 표현식의 일종이다(=함수)/loop는 재귀로 대체된다.
  • ETC(무한 개념의 표현 등)

함수형 언어 종류

  • Haskell
  • SML
  • Clojure
  • Scala
  • Erlang
  • Clean
  • F#
  • ML/OCaml Lisp / Scheme
  • XSLT
  • SQL
  • Mathematica

기본적인 함수형 프로그래밍에서 알면 도움될 용어와 개념

  • Immutable Data(불면 데이터)
  • Closure(클로저)
  • First-class function(1급 함수)
  • Maintainability(유지보수성)
  • Modularity(모듈성)
  • Memoization(메모이제이션)
  • High order function(고차함수)
  • Referential transparency(참조 투명성)
  • Pure function(순수 함수)
  • Currying
    • curried function
    • unary function
    • partial application
  • Point free Style
  • lambda
  • Fold(Left/Right)
  • Monad
  • Arity
  • Auto Currying
  • Function composition
  • Continuation
  • Purity
  • Side effects
  • Idempotent
  • Predicate
    • Consumer
    • Function
    • Supplier
  • Contracts
  • Category
  • Value
  • Constant
  • Functor
  • Pointed Functor
  • Lift
  • Equational Reasoning
  • Lamda Calculus
  • Lazy evaluation
  • Monoid
  • Comonad
  • Applicative Functor
  • Morphism
    • Endomorphism
    • Isomorphism
  • Setoid
  • Semigroup
  • Foldable
  • Lens
  • Type Signatures
  • Algebraic data type
    • Sum type
    • Product type
  • Option
  • Reactive Function Programming
  • Reactive Functional Programming
  • Declarative/Functdional vs Imperative Procedural
  • Optics
  • Reflection
  • Tail call optimization

 Immutable Data 

  • 데이터는 불변한다. 즉 이미 존재하는 데이터를 변경하는 것이 아닌, 데이터 구조를 생성만 할 수 있다. 그리고 변경하지 못한다.
  •  원본 접기
  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    // Mutating your data - you lost your state
    let source = ["h1", "h2", "h3"];
    source[2] = "h4";
    console.log("source");
    console.log(source); // ["h1", "h2", "h4"]


    //No mutation
    source = ["h1", "h2", "h3"];
    let dest = source.map(data => {
      return data == "h3" ? "h4" : data;
    });


    console.log("source");
    console.log(source); // ["h1", "h2", "h3"]
    console.log("result");
    console.log(dest); // ["h1", "h2", "h4"]

 참조투명성(Referential transparency)

  • 프로그램 동작 결과에 무관하게 관련 값을 대체할 수 있는 것.
  •  원본 접기
  • 1 const greet = () => 'Hello World!'

 Closure(클로저)

  • 정의가 매우 다양하다. 
  • 함수가 선언될 당시의 환경(environment)을 기억했다가 나중에 호출되었을때 원래의 환경에 따라 수행되는 함수
  • 정적 스코프가 지정된 바인딩을 구현하는 기술로 이것은 환경과 실행코드(함수)를 표현
  • 범위 외부의 변수에 액세스하는 방법
  • 실행이 정의된 블록 밖으로 이동한 후에도 함수의 로컬변수를 액세스용으로 캡처하는 범위 등

 First class function

  • 컴퓨터 프로그래밍 언어 디자인에서 일급 객체(First class Object)라 함은, 다른 객체들에 일반적으로 적용 가능한 연산을 모두 지원하는 객체를 의미.
  • 즉, 언어 내부에서 값으로 표현되고 전달될 수 있는 자료형 또는 대상을 일급 객체라고 부름.
  • 구체적으로는
    • 함수의 실제 매개변수가 될 수 있어야 한다.
    • 함수의 반환 값이 될 수 있어야 한다.
    • 할당 명령문의 대상이 될 수 있어야 한다.
    • 동일 비교의 대상이 될 수 있어야 한다.
    • 런타임에 함수를 생성할 수 있어야 한다.
  • 함수형 프로그래밍에서 함수는 위 조건을 충족한다.

 Maintainability

  • 함수형 패러다임을 통해 개발된 로직은 유지보수하기 쉽다는 내용을 어필하기 위한 용어.
  • 단순하게 말해 사이드 이펙트가 없으니 수정할 때 두려움이 덜하다는 뜻.

Modularity

  • 문제가 함수 단위로 분해되어 수행되어 모듈 식 설계를 이룰 수 있음을 뜻함.
  • 단위 테스트 및 디버깅에 소요되는 시간을 줄여줌.

Memoization

  • 컴퓨터 프로그램이 동일한 계산을 반복해야 할 때, 이전에 계산한 값을 메모리에 저장함으로써 동일한 계산의 반복 수행을 제거하여 프로그램 실행 속도를 빠르게 하는 기술
  • 동일한 계산을 반복해야 할 경우 한 번 계산한 결과를 메모리에 저장해 두었다가 꺼내 씀으로써 중복 계산을 방지할 수 있게 하는 기법
  • 동적 계획법 알고리즘에서 많이 본 개념
  • 순수 함수 특징으로 같이 나타나는 특징

High order function

  • 함수가 일급 객체로 취급될 때, 함수를 인자로 받거나 결과로 반환하는 함수. 수학에서의 연산자, 범함수와 맥락이 통용된다.
  • 이를 제외한 함수는 일차 함수(first order function).
  •  원본 접기
  • 1
    2
    3
    const filter = (predicate, xs) => xs.filter(predicate)
    const is = (type) => (x) => Object(x) instanceof type
    filter(is(Number), [0, '1', 2, null]) // [0, 2]
  •  

Pure function

  • 동일한 입력값이 주어지면 항상 동일한 결과값을 반환하는 함수
  • 부작용이 발생하지 않음(불변).
  •  원본 접기
  • 1
    2
    3
    const greet = (name) => `Hi, ${name}`


    greet('Brianne') // 'Hi, Brianne'
  •  

Currying

  • 여러 개의 인자를 가진 함수를 호출 할 경우, 파라미터의 수보다 적은 수의 파라미터를 인자로 받으면 누락된 파라미터를 인자로 받는 기법.
  • 다중 인수를 갖는 함수를 단일 인수를 갖는 함수들의 함수열로 바꾸는 것.
  • 커링 구현해보기 정리글(JS)
  •  원본 접기
  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    const sum = (a, b) => a + b


    const curriedSum = (a) => (b) => a + b


    curriedSum(40)(2) // 42.


    const add2 = curriedSum(2) // (b) => 2 + b


    add2(10) // 12

Curried function

  • Currying의 결과물 함수
  •  원본 접기
  • 1
    2
    3
    4
    5
    6
    7
    8
    // Curry function
    // add = argument1 => argument 2 => Number
    const add = arg1 => arg2 => arg1 + arg2;


    // Partial Application
    const addWithTen = add(10);


    console.log(addWithTen(5)); // 15
  •  

Unary function(단항 함수)

  • 단일 인자를 가지는 함수. 커리된 함수(Curried function)는 항상 이 단항 함수를 리턴.

Partial application(부분 적용)

  • 커리된 함수를 통해 인수의 일부의 값이 확정된 함수.
  • 값의 고정이 이뤄지는 경우 클로저를 사용하는 경우도 존재.
  •  원본 접기
  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    // 부분적으로 적용된 함수를 만드는 도우미
    // 함수와 몇 가지 인수를 취합니다.
    const partial = (f, ...args) =>
      // 나머지 인수를 취하는 함수를 반환합니다.
      (...moreArgs) =>
        // 그리고 모두 원래 함수를 호출합니다.
        f(...args, ...moreArgs)


    // 뭔가 적용할 것
    const add3 = (a, b, c) => a + b + c


    // `2`와`3`을 부분적으로 `add3`에 적용하면 하나의 인자로 쓸 수 있습니다
    const fivePlus = partial(add3, 2, 3) // (c) => 2 + 3 + c


    fivePlus(4) // 9

Point free Style or Point free function

  • 함수 정의에 인수를 생략하여 함수를 기술하는 함수 작성 방법.
  • 커링(Curring) 또는 다른 고차 함수를 필요로 함.
  • 불필요하게 인수를 기술하여 코드가 길어지는 것을 방지하고 간셜성과 가독성을 높이는 데 사용.
  •  원본 접기
  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    const samples = Array.from({ length: 10 }, (value, index) => index + 1);




    const double = a => a * a;
    const isEven = a => a % 2 === 0;




    samples
      .map(double) // point free style
      .filter(d => isEven(d));


    // corner case - where signature mismatch happens
    // parseInt => ( string, radix) => Number
    samples.map(parseInt); // [ 1, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, 9]


    // unary helper function - which helps to stream line the signature of the function
    const unary = fn => first => fn.call(this, first);
    samples.map(unary(parseInt)); // [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
  •  원본 접기
  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    // Given
    const map = (fn) => (list) => list.map(fn)
    const add = (a) => (b) => a + b


    // Then


    // Not points-free - `numbers` is an explicit argument
    const incrementAll = (numbers) => map(add(1))(numbers)


    // Points-free - The list is an implicit argument
    const incrementAll2 = map(add(1))

Lambda

  • 값처럼 취급할 수 있는 익명의 함수
  • 이름 없는 함수
  •  원본 접기
  • 1
    2
    3
    4
    5
    ;(function (a) {
      return a + 1
    })


    ;(a) => a + 1

Auto Currying

  • 다항 함수(여러 개의 인수를 취하는 함수)에 필요한 인자 수보다 적은 인자를 전달하면 자동으로 남은 수의 인자를 취하는 함수가 반환되도록 하는 기술.
  •  원본 접기
  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    const add = (x, y) => x + y


    const curriedAdd = _.curry(add)
    curriedAdd(1, 2) // 3
    curriedAdd(1) // (y) => 1 + y
    curriedAdd(1)(2) // 3




    export function curry<A1, R>(fn: (arg1: A1) => R): (arg1: A1) => R;
    export function curry<A1, A2, R>(fn: (arg1: A1, arg2: A2) => R): (arg1: A1) => (arg2: A2) => R;
    export function curry<T extends (...args: any) => any>(fn: T): (...args: any[]) => any {
      return function(...firstArgs) {
        const argsLen = fn.length;
        let allArgs = [];


        return nextArgument(...firstArgs);


        function nextArgument(...args) {
          allArgs = allArgs.concat(args);
          return allArgs.length >= argsLen ? fn.apply(this, allArgs) : nextArgument;
        }
      };
    }

Function composition

  • 한 함수의 출력이 다른 함수의 입력이 되도록 함수를 조합하는 기법.
  •  원본 접기
  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    // composing functions
    const pipe = (...fns) => initData => fns.reduce((arg, fn) => fn(arg), initData);


    const nameInCaps = name => name.toUpperCase();


    const reverseName = name =>
      name
        .split("")
        .reverse()
        .join("");


    const first13Char = name => name.substring(0, 13);


    const greet = name => `${name} to all!!!`;


    const outputFn = pipe(
      reverseName,
      first13Char,
      nameInCaps,
      greet
    )("!!!dnekeew yppah");


    console.log(outputFn); // 'HAPPY WEEKEND to all!!!'
  •  원본 접기
  • 1
    2
    3
    const compose = (f, g) => (a) => f(g(a)) // 정의
    const floorAndToString = compose((val) => val.toString(), Math.floor) // 사용법
    floorAndToString(121.212121) // '121'

Continuation(계속)

  • 함수의 특정 지점에서 코드의 실행이 아직 진행되지 않은 부분
  • 비동기 처리 시 일종의 콜백 영역
  • Coroutine 과 같은 맥락에서 실행의 흐름이 전이하는 경우 각 코루틴의 남은 실행 영역
  • Generator 와 같은 영역에서 yield를 통해 코드 흐름이 중지/분기한 이후 지점

  •  원본 접기
  •  
  • 1
    2
    3
    4
    5
    6
    7
    8
    const printAsString = (num) => console.log(`Given ${num}`)


    const addOneAndContinue = (num, cc) => {
      const result = num + 1
      cc(result)
    }


    addOneAndContinue(2, printAsString) // 'Given 3'
  •  
  •  

Side effects(부수 효과)

  • 함수가 외부 변경 가능 상태와 상호작용하는 일체.
  • 시스템 혹은 프로그램의 상태를 바꾸거나 외부 세계와 상호작용하는 행위.
    • 외부 변수를 변경(전역 변수나 부모 함수 스코프(영역)에 있는 변수 값의 변경)
    • 콘솔에 로깅하기
    • 화면에 데이터를 출력하기
    • 파일 IO 작업
    • 네트워크 요청 보내기
    • 외부 시스템 호출하기
    • 부수 효과가 있는 함수(비순수 함수) 호출하기. 예) new Date() 사용
    • DOM 트리 변경하기
    • DB 접근하기 등
  • 함수형 프로그래밍에서는 이러한 부수 효과가 필요한 경우에 대해 일종의 트릭을 사용함
  •  원본 접기
  • 1 console.log('IO is a side effect!')

Idempotent(멱등성)

  • 함수를 수행한 결과를 다시 그 함수에 적용해도 다른 결과가 나오지 않는다면 그 함수는 멱등성을 가짐
  •  원본 접기
  • 1
    2
    3
    f(f(x)) ≍ f(x)
    Math.abs(Math.abs(10))
    sort(sort(sort([2, 1])))

Predicate(술부)

  • 주어진 인자에 대해 참, 거짓을 리턴하는 함수.
  •  원본 접기
  • 1
    2
    3
    4
    const predicate = (a) => a > 2;




    [1, 2, 3, 4].filter(predicate) // [3, 4]


목록 출처

참고중인 자료

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
TAG
more
«   2025/01   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함