함수형 프로그래밍 배경 지식 1 - Normal World & Wrapper World

Raymond Yoo·2023년 12월 11일
0
post-thumbnail

함수형 프로그래밍은 수많은 순수 함수와 불변 변수를 사용해서
프로그램을 구현하기로 약속하는 것이라고 지금까지 살펴봤다.

그렇지만 다시 생각해보면 부수효과를 일으키지 않는 프로그램이
현실적으로 어떤 가치를 제공할 수 있는지 잘 모르겠다.
코드로 뭔가를 구현해서 실질적으로 의미있는 결과를 내려면
반드시 부수효과를 동반할 수 밖에 없다.
HTTP, TCP 요청을 보내고 응답을 받아서 데이터를 처리하고
데이터베이스에 접근해서 데이터를
저장, 수정하고 이를 가공해야 한다.
로컬스토리지에 접근해서 정보를 일정한 형태로
불러오거나 적재해야 한다.

이런식으로 생각하면
위에서 언급한 함수형 프로그래밍의 두 가지 필수 요소
함수의 참조 무결성(referential integrity) 그리고
변수의 불변성(immutability)과 함께
부수 효과를 효율적으로 다루는 것이 중요하다는 것을 알게 된다.

함수형 프로그래밍에서 부수효과를 다루는 방법을 이해하기에 앞서서
우선 함수형 프로그래머의 눈에 프로그래밍
세상이 어떻게 보이는지 살펴보자.

Normal World and Wrapper World

함수형 프로그래머의 눈에는 세상 모든 변수, 세상 모든 함수가
Normal World 와 Wrapper World 둘 중에
하나에 속한 것으로 보인다.
여기서 Wrapper World 는
Side-Effect World 를 의미하는 것으로
함수형 프로그래밍에서는 모든 변수와 함수를
부수효과가 있는 것과 부수효과가 없는 것으로 나눠서 생각한다고
추상적으로 얘기할 수 있다.
아주 엄밀하게 파고 들면 이런 설명이 틀릴 수도 있지만
생각의 전개를 위해서는 이렇게 생각하면 편하다.
이 두 가지 각각이 무엇을 의미하는지 예시를 통해서 살펴보자.

what is an effect

effect 라는 말이 조금은 광범위하게 사용되는 느낌인데
effect 타입은 wrapper 타입의 일종이고
wrapper 타입은 자신이 감싸는 타입에 다른 의미를 추가한다.
이런식으로 제너릭 타입으로 표현되는 경우는 다
effect 타입, wrapper 타입이라고 생각하면 되고
제너릭 타입에 타입 파라미터로 전달되는 T 타입은
normal world 에 속한다고 생각하면 된다.

Normal World example

Normal World 에 속하는 요소들은 int, string, bool 처럼
wrapper 가 아닌 타입이라고 생각할 수 있다.
기본 타입(primitive type) 뿐만 아니라
User, Pet, Fruit, Employee, Department 와 같은
사용자 정의 타입도 normal 타입의 일종이다.
그리고 입력이 normal 타입이고 출력이 normal 타입인 함수도
Normal World 에 속한 항목 중 하나이다.
int -> string 함수는 normal 타입의 함수이고
User -> Employee 함수도 normal 타입의 함수이다.
이런식으로 wrapper 타입이 아니라면 다 normal 타입에 속한다.

Option World example

Option 이라는 타입은 언어마다 사용하는 단어는 다르지만
어떤값이 있거나 없거나 둘 중에 하나인 상태를
가리키는 wrapper 타입이다.
Option, Optional, Maybe, Either, Nullable 등등
자신의 언어에서 익숙한 타입을 떠올리면 된다.
Option World 는 Normal World 가 아니므로
Wrapper World 의 일종이다.
Option<int>, Option<string>, Option<bool>
Option World 에 속한 항목들이고
Option<T> -> Option<R> 타입의 함수도
Option World 에 속한다.

List World example

이런식으로 Wrapper World 는 엄청 많다.
여기서는 List World 의 예시를 보여주고 있다.

Async World example

Async World 는 다른 언어에서는
Promise, Future, CompletableFuter, Task 등의 용어로
표현하는 개념을 가리킨다.

Effect World example

세상에 존재하는 수많은 Wrapper World 를 추상화해서
Effect World 라고 일컬을 수 있다.
함수형 프로그래밍에서는 이런 effect 타입을 사용해서
부수효과를 적절하게 제어한다.

Normal World, Wrapper World 왕복 횡단 그림

처음에 부수효과를 다루기 위해서 코드를 구현해보면
이 그림과 같은 형태가 된다.
처음에 연산을 시작할때는 Normal World 에 속하는
어떤 값을 담고 있는 변수를 만들게 된다.
이것은 normal 타입의 변수가 될 것이다.
부수효과를 다루기 위한 wrapper 타입으로 만들어서
1단계 처리를 실행한다. 1단계 처리가 완료되었으면
다음 처리를 위해서 wrapper 타입에서 값을 꺼내어
normal 타입 변수에 담는다. 이 변수를
2단계 처리를 위한 아규먼트로 전달한다.
함수형 프로그래밍에서 부수효과를 다룬다는 것은
normal 타입 변수를
wrapper 타입으로 만들어서 태스크를 실행하고
wrapper 타입 응답값에서
다시 normal 타입을 꺼내고
이 꺼낸 값을 다시 wrapper 타입으로 만들어서
처리하는 과정을 반복하는 것이다.

하지만 함수형 프로그래머의 눈에
이렇게 두 가지 서로 다른 World 를 왕복 횡단하는 구조는
지나치게 고생스럽게 느껴진다.
이보다 더 편하고 깔끔하고 우아하게
처리할 방법이 없을까 고민하다가
다음과 같은 구조를 생각해냈다.

Normal World 에서는 시작과 끝에만 접근하고 중간 과정에서 Wrapper World 에만 있음

처리를 시작할때는 입력값을
Normal World 에서 Wrapper World 로 보내지만
중간과정에서는 계속해서 Wrapper World 에만 머무르도록 한다.
여러 단계로 지정한 파이프라인 연산을 모두 거치고 나면 최종결과값은
Wrapper World 에서 Normal World 로 되돌려보낸다.
그러면 Normal World 와 Wrapper World 사이를
횡단하는 과정은 사라져서
전체적인 구조는 훨씬 간소화되었지만
입력값과 결과값은 여전히 그대로이다.

이런 추상적인 아이디어를 코드레벨에서 구현하면
어떤 형태가 되는지 예시를 통해서 천천히 살펴보자.

<참조>
유뷰트 영상, The Absolute Best Intro to Monads For Software Engineers
유뷰트 영상, Functional Design Patterns - Scott Wlaschin

profile
세상에 도움이 되고, 동료에게 도움이 되고, 나에게 도움이 되는 코드를 만들고 싶습니다.

0개의 댓글