함수형 프로그래밍 스터디 - 1, 함수형 길들이기

horiz.d·2023년 6월 19일
0

본 글은 함수형 자바스크립트: 모던 웹 개발에 충실한 실전 함수형 프로그래밍 안내서 스터디를 통해 작성된 내용입니다.

horizontal-library - FP 스터디 - 함수형 길들이기

p.26

함수형 프로그래밍의 목표는 '부수효과(side effect)'를 방지하고 '상태변이(mutation of state)' 감소시키기 위해 데이터의 제어 흐름과 연산을 '추상'하는 것이다.


p.27

함수형 프로그램은 여러 함수를 서로 합성하고 평가해서 더 많은 기능을 탑재하는 것이 유일한 목표이다.

var printMessage = run(addToDom('msg'), h1, echo);

printMessage('Hello World');

해당 예제의 run 함수는 매개변수의 세 함수를 체인처럼 연결하여, 한 함수의 반환값이 다른 함수의 입력값으로 전달되게끔 한다.

위의 run 함수의 세 개의 매개변수는 단순 스칼라 값이 아니라, 각각 인자를 갖는 함수형 매개변수로, 작은 함수들을 재료로 새로운 함수를 만들어 내는 것 이라고 이해할 수 있다. 더 작은 조각들로 프로그램을 나누고, 전체적으로 헤아리기 쉬운 형태의 프로그램으로 재조합 하는 것, 모든 함수형 프로그램은 이 기본원리를 따라 작성된다.

이는 본연의 기능은 그대로 간직한 채 코드를 쉽게 변경하기 위해 코드 자체를 매개변수화 하는 것이다.



함수형 프로그래밍은 선언적 (p.28~30)

함수형 프로그래밍은 선언적 프로그래밍 패러다임이다.

선언적 프로그래밍은 (명령형 프로그램과는 달리), 프로그램의 서술부평가부를 분리하여, 내부 메커니즘은 추상한 상태에서 로직이 무엇인지 표현식으로 서술한다.
(+)

  • 서술부 : 함수의 동작을 서술하는 부분으로, 전역레벨에서는 추상화 된다고 이해하면 될 것 같다.
  • 평가부 : FP의 함수는 평가라는 표현으로 호출에 의한 실행을 표현한다.

일반 루프는 함수로 추상하지 않는 한 재사용 자체가 안된다. 따라서, 함수를 매개변수로 받는 일급 고계함수(map,reduce, filter...)로 대체하여 재사용성과 확장성을 높일 수 있고, 이러한 루프를 함수로 추상하는 결과로 ES6의 람다 표현식과 화살표 함수 를 사용할 수 있다.

( + 람다 표현식은 함수의 인자로 전달 가능한 익명 함수를 대체할 수 있는 깔끔한 대체 수단이다)

왜 수동루프를 제거해야 하는가?
1. 수동루프는 재사용이 어려우며 다른 연산간의 삽입도 어려운 명령형 제어 구조물이다.
2. 루프는 성격상 반복 시 값이나 상태가 계속 바뀐다. FP는 무상태성불변성을 지향하므로 순수함수를 사용해야 한다.

-> 여기서 언급된 루프의 상태의 변화에 대해, 고계함수의 경우에도 결국 루프의 동작을 수행하는데 무엇이 다른가? 의문이 있었고, 스터디 중 Jason에게 물어보고 논의해보았다. 루프의 상태가 바뀐다는 것은, 전역레벨에서 추상화되지 않아 외부노출되는 루프의 인덱스 및 루프의 명령부에 임의의 작업이 추가되어 반복 진행 중 인덱스가 예측 불가능하게 변할 수 있는 문제를 표현하는 것 이라고 논의를 가졌고, 고계함수는 루프동작과 로직은 각각 추상화 및 모듈화되어 예기치 못한 상태변화에 의해 결과가 영향을 받지 않는다고 이해할 수 있었다.

순수함수와 부수효과 (p.30~35)

함수형 프로그래밍은 순수함수로 구성된 불변 프로그램의 구축을 전제로 한다.

순수함수의 특성
1. 주어진 입력에만 의존한다. 숨겨진 값이나 외부 상태와 무관하게 작동한다.
2. 전역 객체, 원본 매개변수 수정 등 함수 스코프 밖에서 어떤 변화도 일으키지 않는다.

-> 이 요건 위배 시 불순, impure한 함수이며, side effect를 일으킬수 있다.

부수효과 발생 상황
1. 전역범위 접근 및 수정
2. 함수의 원래 인자값 변경 ( 객체를 레퍼런스로 넘기고 객체에 수정 및 변이를 발생, (ex.배열 Array.sort 메서드 등) )
3. 사용자 입력 처리
4. 예외 시 throw처리에 의한 함수 종료
5. 출력
6. HTML 문서, 브라우저 쿠키, DB 등 외부소스 접근, 질의, 수정 (심지어는 Date.Time)

-> 하지만 DB 등 필수적인 외부자원 접근을 제거하는 것은 불가능할 수 있다. 따라서 완벽한 불순한 로직 제거는 불가능할 수 있다.
-> 함수형 프로그래밍의 목표는 불순함수의 최소화 및, 불순함수와 순수함수의 분리이다. 따라서 불가피한 경우 분리시켜 관리하는 것으로 해결할 수 있다. 이 때 커링 을 이용할 수 있다.
(+ 커링이란?, 수학과 컴퓨터 과학에서 커링(currying)이란 다중 인수 (혹은 여러 인수의 튜플)을 갖는 함수를 단일 인수를 갖는 함수들의 함수열로 바꾸는 것을 말한다.)



참조투명성과 치환성, (p35 ~ 37)

참조투명성은 순수함수를 정의하는 더욱 공식적 방법이다.
여기서 순수성이란 **함수의 인수와 결과값 사이 순수한 매핑관계`를 말한다.
따라서, 함수가 동일 입력에 대해 동일 결과를 낼 경우 참조투명한 함수라고 말할 수 있다.

함수가 의존하는 상태, 즉, 외부 자원등을 제거하고 함수 시그니처에 정규 매개변수로 명시하는 방법을 사용하여 순수성을 제고할 수 있다.

참조 투명성은 전적으로 개발자의 숙제로 남는다.

참조투명한 함수는 항상 옳은 결과를 내며 에러가 날 수 없다.
참조투명하다는 것은 결과 예측이 가능하고, 로직 파악이 용이하며, 항상 옳은 결과를 내놓기 때문에 시스템의 상태를 머릿속으로 그려볼 수 있으며(멘털 모델), 코드를 재작성 혹은 치환화더라도 원하는 결과를 예측 및 얻을 수 있으므로 헤아리기 쉽다.

또한, 100% 순수함수의 경우 프로그램의 함수를 수식화 하여 표현할 수 있다. 이런 참조 투명성을 통해, 거의 수학적인 형태로 프로그램을 헤아릴 수 있다.



복잡한 작업 분해 유도 (p.39 ~ 40)

함수형 프로그래밍은 고수준(전역레벨 쯤?)에서 보면 분해와 합성간의 상호작용이며, 모듈적 효율적이다.
이 때, 작업단위(unit)는 바로 함수 자신이다.

FP에서 모듈화는 단일성의 원리와 밀접한 관련이 있다.
함수는 저마다 한가지 목표를 바라봐야 한다.

( + 이에 대해 Jason과 의논해 본 결과, FP의 작업단위 함수 분리는 OOP의 단일책임 원칙과 비슷하다고 보았으며, 사실 OOP와 FP는 서로 배타적인 패러다임이 아니며 FP는 OOP를 어느정도는 품고 있다는 사실을 이해할 수 있었다. 다만, 함수형 프로그램은 더욱 프로그램적인 입장에서 고려하기 때문에, 순수 기능단위로 작업을 분리한다는 것이 조금 다를 수 있다는 것을 인지했다.)

단순 함수를 엮어 붙이기 위해(합성) 반드시 입출력을 맞춰줘야 한다. 이에 따라, f ( g( x ) ) 합성함수의 경우, g의 반환값과
f의 인자의 개수와 형식(타입)을 일치 시켜야 한다. 이를 통해 f와 g는 느슨하고, 형식 안전한 관계가 맺어진다.

함수 합성은 고수준의 추상화를 통해 자세한 구현을 보여주지 않고(black box) 전 단계를 일목요연하게 나타낸다.



데이터를 매끄럽게 체이닝 처리, ( p41 ~ 42)

체인 은 같은 객체를 반환하는 순차적인 함수호출이다.

로대시JS, 람다JS등 함수형JS도구에는 이를 위한 고계함수가 구현되어 있으며, 리액티브JS에서도 활발히 사용된다.

함수 체인은 필요한 시점까지 실행을 미루는 지연 평가(느긋한 평가, Lazy evaluation, 수직적)를 수행한다.

(+ 지연평가Call By Need로 작동하며, 즉시 평가되어 수평적으로 불필요한 값을 처리하지 않고, 수직적으로 개별 item에 대해 모든 체인을 수행하며 나아간다. 이에 따라 불필요한 items까지 로직을 처리하지 않으며, cpu 및 메모리의 절약을 제고할 수 있다. )

복잡한 비동기 앱에서도 신속하게 반응, ( p43 ~ 45 )

외부 소스 조회 등에 사용되는 콜백 패턴은 성공/실패 로직이 중첩된 형태로 흩뿌려져 있기 때문에 코드의 선형 흐름이 깨지며 동작을 파악하기 어렵다. 반면, FP의 응용분야 리액티브 프로그래밍에선 고차원의 코드 추상화, 비동기,이벤트 기반 프로그램처리를 위한 보일러 플레이트를 없애고(추상화하여 재사용), 비즈니스 로직에만 전념할 수 있게 한다.

profile
가용한 시간은 한정적이고, 배울건 넘쳐난다.

0개의 댓글