본문 바로가기

호기심 천국

리액트와 대수적 효과는 무슨 관계일까?

겨울 참새.  사진: Unsplash 에 Łukasz Rawa 님이 올림.

요약

리액트가 대수적 효과의 어떤 아이디어를 참고해 그것과 비슷한 결과를 내는 건 맞지만, 구현 단계에서 직접적인 관련은 없는 듯 합니다.

들어가는 말

리액트의 Suspense를 공부하다 보면 한번쯤 '대수적 효과'의 이야기를 들어봤을 겁니다. 솔직히 궁금했어요. 컴퓨터가 수학으로 돌아가는 럭키 계산기인 건 맞지만 '리액트가 수학인가?'는 아닌 것 같다고 생각했거든요. 리액트 공식 문서에서도 대수학(algebra) 얘기는 꺼내질 않는데 도대체 대수적(algebraic) 효과가 뭐길래 저와 리액트의 관계를 방해하는 건지 궁금했습니다.

 

리액트 팀의 Dan Abramov 선생님이 쓴 글에 리액트와 대수적 효과에 관해 친절하고 자세한 설명이 있었지만, 그래서 '대수적 효과'가 도대체 뭔지는 제대로 알려주지 않았습니다. 근데 알려주지 않은 이유가 있더라구요. 지금의 제 지식 수준으로는 이해할 수 없는 높은 수준의 개념이었습니다. 알려주지 않은 이유도 진짜 '몰라도 되니까'가 맞는 것 같아요. 크게 세 가지 이유가 있다고 봅니다.

 

  1. 함수형 프로그래밍에 대해 정말로 깊은 지식과 이해가 필요함
  2. 자바스크립트는 '대수적 효과'를 케어할 수 있는 기능이 아예 없음
  3. 리액트는 대수적 효과의 '결과물'에 집중해 대수적 효과로 달성하고자 하는 목표를 다른 방식으로 구현해서 달성했기 때문에, 대수적 효과의 내부 동작을 이해할 필요가 없음

이상이 제 핑계입니다. 제가 조사한 내용에 대해서는 적겠지만, 이걸 제가 이해했다고는 할 수 없습니다. 몇 편의 논문을 보기는 했지만 그 안의 수식들은 단 한 줄도 이해하지 못했거든요(이해하고 싶지 않았던 것일수도 있구요). 그래서 저는 이 글이 제대로 된 글이라고 생각하지 않습니다. 그럼에도 불구하고 읽어주시겠다면 먼저 감사하다는 말씀을 드리고 싶네요.

대수 구조(algebraic structure)

대수적 효과라는 말을 이해하기 위해서는 대수학이 뭔지부터 알아야 한다고 생각했습니다. 어떻게 보면 단어의 모체일 테니까요. 대수학은 대수적 구조에 대해 연구하는 학문이라고 하기에, 다시 대수적 구조가 뭔지 찾아보기로 했습니다. 위키피디아의 설명을 요약하면 대수적 구조의 정의는 대략 다음과 같습니다.

공집합이 아닌 집합 A와 A에 대한 연산들, 이 연산들이 따라야 하는 유한 개의 공리가 포함된 구조

 

도대체 이게 대수적 효과와는 무슨 상관이며, 더 나아가 리액트와는 무슨 관련이 있는 걸까요?

대수적 효과(algebraic effects)

먼저 Pretnar(2015) 선생님의 논문을 보겠습니다.

Algebraic effects are an approach to computational effects based on a premise that impure behaviour arises from a set of operations such as get & set for mutable store, read & print for interactive input & output, or raise for exceptions. This naturally gives rise to handlers not only of exceptions, but of any other effect, yielding a novel concept that, amongst others, can capture stream redirection, backtracking, co-operative multi-threading, and delimited continuations.

 

크게 다음과 같은 내용들을 추려낼 수 있겠군요.

 

  1. Computational effects 와 관련됨.
  2. 순수하지 않은 행동들은 연산들의 집합에서 비롯됨.
  3. 대수적 효과의 처리를 위해서 stream redirection, backtracking, multi-threading, delimited continuation 등이 가능한 핸들러가 등장함.

다음으로 Plotkin과 Pretnar(2013) 선생님들의 논문을 보겠습니다.

Algebraic effects are computational effects that can be represented by an equational theory whose operations produce the effects at hand.

 

  1. effect를 만들어내는 연산들로 표현 가능한 computational effect 임.

방정식론은 진짜 모르겠어서 못 적겠어요.

 

마지막으로 또다시 Plotkin과 Pretnar(2009) 선생님들을 모셨습니다.

algebraic effects, that is effects that allow a representation by operations and equations.

In the algebraic approach the arguments of an operation represent possible computations after an occurrence of an effect.

 

  1. 대수적 효과는 식과 연산으로 표현 가능한 효과(effect)임.
  2. 대수적 접근법을 쓰면 연산의 인수(argument)는 effect의 실행 결과물을 나타낼 수 있음.

쉽지 않네요. 근데 적으면서 느낀 건데 쓰신 분들이 다 같은 사람들이라 내용이 비슷한 것 같기도 합니다.

 

요약하면 대수적 효과는 대략

 

  1. 식과 연산으로 표현 가능한 computational effect.
  2. 연산의 인수로 effect의 실행 결과물이 들어갈 수 있음.
  3. computational effect는 순수하지 않을 수 있음.
  4. 대수적 효과는 핸들러로 처리 가능함.

이런 친구인 것 같습니다. 일단은 유한 개의 식과 연산으로 표현 가능하다는 점에서 대수 구조와 연관성이 있어서 이런 이름이 되지 않았나 싶네요. 그리고 대수적 효과는 핸들러라는 외부 함수가 처리하고, 이 핸들러의 결과물을 다시 원래 연산의 인수로 넣을 수 있는 것으로 보입니다.

Computational Effects

('계산 효과'라고 검색했더니 아무것도 안 나와서 그냥 영어로 씁니다.)


왠지 안 찾아봐도 '느낌'만큼은 오는 단어지만, 여기까지 왔으니 한 번은 보고 가야죠. Plotkin과 Power(2004) 선생님들은 이렇게 말합니다.

Part of the enterprise of the semantics of programming languages is to separate out and analyse their features. One such is that of side-effects, the “side”indicating that they occur “on the side” while polymorphically computing something else (or, in the case of commands, nothing at all). Side-effects concern the store, but one can see other features similarly as polymorphic effects: examples are various forms of nondeterminism, printing, or jumps of various kinds. These computational effects form the focus of our investigation. Computational effects invariably arise from operations such as a nondeterministic choice operation, operations for writing or reading, or operations for looking up or updating state.

 

대충 저장소를 건드리는 side effect를 포함하여 비결정적(동일 입력이더라도 결과가 매번 다를 수 있는)인 것, 입출력, 단순히 외부 상태를 참조하는 것 등의 다양한 행동들을 모두 포함하는 게 computational effect 라고 합니다. 닫힌계가 아닌 함수에서 외부 세계와 소통하려는 모든 시도를 computational effect 라고 칭하는 것 같네요.

'순수하지 않다'?

문학적이네요. 하지만 냉혹한 코딩의 세계에서 함수의 순수성이 뜻하는 바는 많은 분들이 알고 계실 겁니다. 같은 입력에 대해서는 같은 결과가 나와야 하고, 부수 효과(외부 상태를 건드리는 것)가 없는 함수가 순수한 친구죠. 그 반대가 순수하지 않은 함수입니다. 어떤 전역 객체를 건드리거나, 서버와의 통신을 해야 해서 결과가 확실하지 않은 것들이 순수하지 않은 함수의 대표적인 예시들이죠.

또 하나의 특징: 관심사의 분리

대수적 효과는 '만드는 쪽'과 '처리하는 쪽'이 분리되어 있습니다. 만드는 쪽에서는 대수적 효과를 통해 '무엇을' 하고 싶은지(ex. 나 사용자가 입력한 숫자가 필요해)를 말합니다. 그러면 핸들러는 '어떻게' 그 소원을 이뤄줄 것인지(ex. 이러저러한 과정을 통해서 사용자의 키보드를 인식하고 어쩌구저쩌구해서 값을 읽어오면 되겠군)에 집중하죠. 이 두 가지를 분리하여 선언적인 코드를 짤 수 있다는 점을 대수적 효과와 핸들러라는 개념의 장점이라고 생각합니다. 마치 try/catch 와 비슷하지만, 대수적 효과의 핸들러는 catch 후 다시 실패했던 지점으로 돌아갈 수 있다는 큰 차이가 있습니다.

리액트와 대수적 효과

사실 이 부분은 Dan Abramov 선생님이 쓴 글을 꼭 보시는 걸 추천해요. 저도 저거 보고 쓴 거니까요.

Suspense

Suspense는 밖에서 대충 보면 자식 컴포넌트가 렌더링하다가 던진 Promise를 받아서 그 Promise의 resolve를 기다리고, 완료되면 그 값을 가지고 자식 컴포넌트의 렌더링을 재개하는 걸로 보입니다. 대수적 효과와 연관지어서 생각해 봅시다. 외부 세계의 힘으로 처리해야 하는 promise를 던지고, 그 promise를 Suspense가 잡아서 핸들링합니다. 그리고 그걸 다시 자식 컴포넌트에게 돌려주면 '일시정지' 되었던 렌더링 함수가 다시 '재생'되죠. 위에 적혀 있던 backtracking(던졌던 자식 컴포넌트의 위치를 찾아가기), delimited continuation(일시정지된 함수를 딱 한번만 재생할 수 있다는 제약이 있지만 어쨌든 재생함) 이라는 대수적 효과의 핸들러가 갖는 특징과 비슷합니다. 핸들러의 실행 결과물이 다시 렌더링 함수의 인수처럼 사용된다는 점도 유사하네요.

 

물론 실제로는 일시정지된 렌더링 함수를 재생하는 게 아니라 다시 렌더링 함수를 호출해서 처음부터 그리는 것이긴 하지만, 컴포넌트의 렌더링 함수는 순수해야 한다는 리액트의 규칙이 마치 '일시정지 후 재생' 처럼 보이게 하는 것이죠. 어쨌든 대수적 효과와 그 핸들러를 사용하지는 않았지만 그 친구들이 하는 일을 모방하긴 했습니다.

useState

리액트 상태를 받아오는 과정도 대수적 효과와 핸들러 개념으로 설명은 할 수 있습니다. 우리가 useState를 쓸 때 '이 useState는 무슨무슨 이름을 가진 컴포넌트의 몇 번째 상태야'라고 하지 않습니다. 그냥 컴포넌트가 '나 상태 줘'라고 하면 컴포넌트 외부 세계의 핸들러(리액트)가 알아서 상태를 찾아서 줄 뿐이죠. 리액트를 핸들러라고 한다면 핸들링 후 상태값을 다시 컴포넌트에게 돌려주고, 그 값을 가지고 렌더링을 재개하는 것처럼 해석할 수 있습니다.

 

물론 실제로는 현재 컴포넌트와 그 컴포넌트의 상태를 찾아올 수 있는 dispatcher 를 알고 있기 때문에, 무책임하게 던지는 게 아니라 스스로 잘 찾아오는 건실한 컴포넌트라고 합니다.

결론

뱁새가 황새를 따라가면 가랑이가 찢어진다고 했던가요. 참으로 맞는 말입니다. 왜 리액트와 대수적 효과를 연관지어서 설명할 수 있는지는 어느 정도 알겠습니다. 하는 짓을 대수적 효과와 핸들러로 인한 관심사 분리 측면에서 해석할 수는 있거든요. 근데 그거 말고는 모르겠습니다. 애초에 대수적 효과를 지원하지 않는 자바스크립트고 그 자바스크립트로 만든 게 리액트인데, 누군가 리액트에 대수적 효과라는 독을 풀었다는 생각밖에는 들지 않네요.

참고 자료

정보의 바다

overreacted - Algebraic Effects for the Rest of Us
[10분 테코톡] 클린의 서스펜스와 에러바운더리
Wikipedia - Algebraic structure
Algebraic Effects of React Suspense

곰국

Plotkin, G. D., & Pretnar, M. (2013). Handling algebraic effects. Logical methods in computer science, 9.
Pretnar, M. (2015). An introduction to algebraic effects and handlers. invited tutorial paper. Electronic notes in theoretical computer science, 319, 19-35.
Plotkin, G., & Pretnar, M. (2009, March). Handlers of algebraic effects. In European Symposium on Programming (pp. 80-94). Berlin, Heidelberg: Springer Berlin Heidelberg.
Plotkin, G., & Power, A. J. (2004). Computational effects and operations: An overview. Electronic Notes in Theoretical Computer Science, 73, 149-163.

'호기심 천국' 카테고리의 다른 글

MVC  (0) 2024.04.27
TanStack Query) staleTime 'Infinity' 는 어떻게 아는걸까?  (0) 2024.04.06
TypeScript) enum vs as const  (2) 2024.03.24
리액트 동시성이란  (2) 2024.03.09
CSS) border vs outline  (0) 2024.02.23