논리와 메모리 - 논리와 저수준(Low-level) 자료 표현(Data representation) (2 편 중 2 편)

Ailrun (UTC-5/-4) @ailrun@hackers.pub

논리와 저수준(Low-level) 자료 표현(Data representation) 연작

  • 1 편
  • 2 편 \text{---} 이 글

다시 보는 논리적이 되는 방법 - 논건 대수(論件 代數, Sequent Calculus)

1 편에서 다루었던 "논리적"이 되는 두번째 방법, 즉 논건 대수를 다시 한 번 짚고 넘어가자. 우선 논건 대수에서 다루는 대상은

명제의 진리 대한 가정적 판단 ΓP true\Gamma \vdash P\ \texttt{true}

였다. 여기서 명제란

  1. 단위 명제(Atomic Proposition) AA
  2. 참 명제(True Proposition) \top
  3. 거짓 명제(False Proposition) \bot
  4. 명제 PPQQ가 있을 때, PQP \land Q(PP 그리고 QQ)
  5. 명제 PPQQ가 있을 때, PQP \lor Q(PP 또는 QQ)
  6. 명제 PPQQ가 있을 때, PQP \to Q(PP라면 QQ)

같은 방법을 통해 만들어질 수 있는 대상이었다.

논건 대수에서는 이 명제의 진리에 대한 가정적 판단이 논리적인지 아닌지를 다음과 같은 추론 규칙에 기반하여 증명했다.

P trueΓΓP trueinitΓP trueΓ,P trueQ trueΓQ truecut Γ trueR Γ, trueP trueLΓP trueΓQ trueΓPQ trueRΓ,P true,Q trueR trueΓ,PQ trueR trueLΓP trueΓPQ trueR1ΓQ trueΓPQ trueR2Γ,P trueR trueΓ,Q trueR trueΓ,PQ trueR trueLΓ,P trueQ trueΓPQ trueRΓP trueΓ,Q trueR trueΓ,PQ trueR trueL \global\def\tJ#1{#1\ \texttt{true}} \begin{equation} \begin{array}{c} \cfrac {\tJ P \in \Gamma} {\Gamma \vdash \tJ P} \text{init} \qquad \cfrac {\Gamma \vdash \tJ P \qquad \Gamma, \tJ P \vdash \tJ Q} {\Gamma \vdash \tJ Q} \text{cut} \newline\newline\newline \cfrac {\ } {\Gamma \vdash \tJ \top} \text{R}\top \qquad \cfrac {\ } {\Gamma, \tJ \bot \vdash \tJ P} \text{L}\bot \newline\newline\newline \cfrac {\Gamma \vdash \tJ P \qquad \Gamma \vdash \tJ Q} {\Gamma \vdash \tJ{P \land Q}} \text{R}\land \qquad \cfrac {\Gamma, \tJ P, \tJ Q \vdash \tJ R} {\Gamma, \tJ{P \land Q} \vdash \tJ R} \text{L}\land \newline\newline\newline \cfrac {\Gamma \vdash \tJ P} {\Gamma \vdash \tJ{P \lor Q}} \text{R}\lor_1 \qquad \cfrac {\Gamma \vdash \tJ Q} {\Gamma \vdash \tJ{P \lor Q}} \text{R}\lor_2 \newline\newline \cfrac {\Gamma, \tJ P \vdash \tJ R \qquad \Gamma, \tJ Q \vdash \tJ R} {\Gamma, \tJ{P \lor Q} \vdash \tJ R} \text{L}\lor \newline\newline\newline \cfrac {\Gamma, \tJ P \vdash \tJ Q} {\Gamma \vdash \tJ{P \to Q}} \text{R}\to \qquad \cfrac {\Gamma \vdash \tJ P \qquad \Gamma, \tJ Q \vdash \tJ R} {\Gamma, \tJ{P \to Q} \vdash \tJ R} \text{L}\to \end{array} \end{equation}

각 추론규칙은 줄 위의 판단(전제)을 증명했을 때 줄 아래의 판단(결론)을 증명하는 규칙이다.

1 편에서 논건 대수는 위의 규칙 중 cut\text{cut}을 제거함으로서 일관적임, 즉 거짓을 증명할 수 없는 체계임을 쉽게 보일 수 있게 만든 것이라 설명했다. 또한 이 체계가 가지는 단점(증명에 대응되는 컴퓨터 공학적으로 직관적인 항을 주기 어려움) 역시 다루었다.

그렇다면 논건 대수는 컴퓨터 공학적으로 쓸모가 없을까? 물론 아니다! 아주 약간의 변형을 통해 컴퓨터 공학적으로 유용한 해석이 가능한 항을 줄 수 있다. 이 해석을 주기에 앞서 어떤 변형이 필요한지에 대해 먼저 알아보자.

논건 대수 변형하기 - 반(半)공리적 논건 대수(Semi-Axiomatic Sequent Calculus)

우선 접근 방식의 근간을 변경하도록 하자. 이전에는 논건 대수의 일관성을 보이기 위해 cut\text{cut} 규칙을 없애는 데에 초점을 맞추고 있었다. 반면에 이제는 컴퓨터 공학적으로 유용한 해석을 주는데에 집중해서, cut\text{cut} 규칙을 없애는 대신에 최대한 활용하려고 해보자. 이런 관점에서는 논건 대수의 몇몇 규칙은 쓸데없는 복잡도를 가지고 있다. 다른 말로는 이런 규칙들은 cut\text{cut}이 이미 담당한 일과 일부 겹치는 일을 하고 있다. 예를 들어

ΓP trueΓQ trueΓPQ trueR \global\def\tJ#1{#1\ \texttt{true}} \begin{equation} \begin{array}{c} \cfrac {\Gamma \vdash \tJ P \qquad \Gamma \vdash \tJ Q} {\Gamma \vdash \tJ{P \land Q}} \text{R}\land \end{array} \end{equation}

규칙을 사용하기 위해서는 P trueP\ \texttt{true}Q trueQ\ \texttt{true}를 전제로 먼저 증명해야만 한다. 다음의 변형된 규칙에서처럼 가정에 P trueP\ \texttt{true}Q trueQ\ \texttt{true}가 이미 주어졌다고 하는 것으로 규칙을 서술한다면 이 "먼저 증명해야함"이라는 규칙의 복잡도를 피할 수 있다.

 Γ,P true,Q truePQ trueAR \global\def\tJ#1{#1\ \texttt{true}} \begin{equation} \begin{array}{c} \cfrac {\ } {\Gamma, \tJ P, \tJ Q \vdash \tJ{P \land Q}} \text{AR}\land \end{array} \end{equation}

이 변형된 규칙 AR\text{AR}\land는 따로 놓고 보았을 때는 원래의 R\text{R}\land보다 증명할 수 있는 판단이 적지만, cut\text{cut} 규칙을 최대한 활용한다면 같은 능력을 지닌다. 원래의 규칙을 다음과 같은 꼴로 대체할 수 있기 때문이다[1].

 ΓP true ΓQ true Γ,P true,Q truePQ trueARΓ,P truePQ truecutΓPQ truecut \global\def\tJ#1{#1\ \texttt{true}} \begin{equation} \begin{array}{c} \cfrac {\begin{array}{c} \ \\ \Gamma \vdash \tJ P \end{array} \qquad \cfrac {\begin{array}{c} \ \\ \Gamma \vdash \tJ Q \end{array} \qquad \cfrac {\ } {\Gamma, \tJ P, \tJ Q \vdash \tJ{P \land Q}} \text{AR}\land} {\Gamma, \tJ P \vdash \tJ{P \land Q}} \text{cut}} {\Gamma \vdash \tJ{P \land Q}} \text{cut} \end{array} \end{equation}

다시 말해서 R\text{R}\landAR\text{AR}\land라는 "순수한 \land를 위한 규칙"과 cut\text{cut}으로 분해할 수 있다. 여기서 AR\text{AR}\land와 같이 어떤 전제도 가지지 않은 추론 규칙을 "공리"("Axiom")라고 한다. 이 규칙이 A\text{A}로 시작하는 이름을 가지는 이유도 바로 이 규칙이 공리(Axiom)이기 때문이다. 같은 방법을 다음의 R1\text{R}\lor_1 규칙

ΓP trueΓPQ trueR1 \global\def\tJ#1{#1\ \texttt{true}} \begin{equation} \begin{array}{c} \cfrac {\Gamma \vdash \tJ P} {\Gamma \vdash \tJ{P \lor Q}} \text{R}\lor_1 \end{array} \end{equation}

에 적용하면 다음의 공리를 얻을 수 있다.

Γ,P truePQ trueAR1 \global\def\tJ#1{#1\ \texttt{true}} \begin{equation} \begin{array}{c} \cfrac {} {\Gamma, \tJ P \vdash \tJ{P \lor Q}} \text{AR}\lor_1 \end{array} \end{equation}

또한 R2\text{R}\lor_2에도 마찬가지 변환을 적용해 공리 AR2\text{AR}\lor_2를 얻어낼 수 있다.

지금까지 R\text{R}\landR1\text{R}\lor_1, R2\text{R}\lor_2를 공리로 바꾸어 cut\text{cut}이 하는 일과 중복되는 "쓸데없는" 복잡도를 줄여보았다. 그렇다면 공리로 바꿔 쓸 "쓸데없는" 복잡도는 항상 R\text{R} 규칙이 가지고 있을까? 안타깝게도 그리 단순하지만은 않다. PQP \to Q를 위한 규칙의 경우 R\text{R}\to 규칙이 아닌 다음의 L\text{L}\to 규칙

ΓP trueΓ,Q trueR trueΓ,PQ trueR trueL \global\def\tJ#1{#1\ \texttt{true}} \begin{equation} \begin{array}{c} \cfrac {\Gamma \vdash \tJ P \qquad \Gamma, \tJ Q \vdash \tJ R} {\Gamma, \tJ{P \to Q} \vdash \tJ R} \text{L}\to \end{array} \end{equation}

에서만 cut\text{cut}이 하는 일과 겹치는 부분을 관찰할 수 있고, 이를 다음과 같이 제거할 수 있다.

 Γ,P true,PQ trueQ trueAL \global\def\tJ#1{#1\ \texttt{true}} \begin{equation} \begin{array}{c} \cfrac {\ } {\Gamma, \tJ P, \tJ{P \to Q} \vdash \tJ Q} \text{AL}\to \end{array} \end{equation}

명제를 만드는 방법들이 가지는 이 차이, 즉 cut\text{cut}과 겹치는 일을 하는 규칙이 R\text{R} 규칙인 방법(\land\lor)과 L\text{L} 규칙인 방법(\to)의 차이가 인위적인 차이로 보일지 모르나, 이 차이는 사실 논리적으로 매우 자연스럽고 중요한 여러 결과들을 주며 컴퓨터 공학적으로도 직관적인 구분을 준다. 이로 인해 이 두 방법에

  • 양(Positive)의 방법: R\text{R} 규칙이 공리로 바뀌어야 하는 명제를 만드는 방법 (\land\lor)
  • 음(Negative)의 방법: L\text{L} 규칙이 공리로 바뀌어야 하는 명제를 만드는 방법 (\to)

같이 이름을 붙이기도 한다. 이후의 절에서 컴퓨터 공학적으로 이 둘이 어떻게 구분되는지에 대해 설명하며 이 이름을 사용할 것이다.

지금까지 cut\text{cut} 규칙을 최대한 활용할 수 있도록 다른 규칙들에서 cut\text{cut} 규칙이 담당한 일과 중복되는 부분을 최대한 제거해보았다. 요약하자면 다음과 같은 규칙들을 얻었다.

P trueΓΓP trueinitΓP trueΓ,P trueQ trueΓQ truecut Γ trueR Γ, trueP trueL Γ,P true,Q truePQ trueARΓ,P true,Q trueR trueΓ,PQ trueR trueL Γ,P truePQ trueAR1 Γ,Q truePQ trueAR2Γ,P trueR trueΓ,Q trueR trueΓ,PQ trueR trueLΓ,P trueQ trueΓPQ trueR Γ,P true,PQ trueQ trueAL \global\def\tJ#1{#1\ \texttt{true}} \begin{equation} \begin{array}{c} \cfrac {\tJ P \in \Gamma} {\Gamma \vdash \tJ P} \text{init} \qquad \cfrac {\Gamma \vdash \tJ P \qquad \Gamma, \tJ P \vdash \tJ Q} {\Gamma \vdash \tJ Q} \text{cut} \newline\newline\newline \cfrac {\ } {\Gamma \vdash \tJ \top} \text{R}\top \qquad \cfrac {\ } {\Gamma, \tJ \bot \vdash \tJ P} \text{L}\bot \newline\newline\newline \cfrac {\ } {\Gamma, \tJ P, \tJ Q \vdash \tJ{P \land Q}} \text{AR}\land \qquad \cfrac {\Gamma, \tJ P, \tJ Q \vdash \tJ R} {\Gamma, \tJ{P \land Q} \vdash \tJ R} \text{L}\land \newline\newline\newline \cfrac {\ } {\Gamma, \tJ P \vdash \tJ{P \lor Q}} \text{AR}\lor_1 \qquad \cfrac {\ } {\Gamma, \tJ Q \vdash \tJ{P \lor Q}} \text{AR}\lor_2 \newline\newline \cfrac {\Gamma, \tJ P \vdash \tJ R \qquad \Gamma, \tJ Q \vdash \tJ R} {\Gamma, \tJ{P \lor Q} \vdash \tJ R} \text{L}\lor \newline\newline\newline \cfrac {\Gamma, \tJ P \vdash \tJ Q} {\Gamma \vdash \tJ{P \to Q}} \text{R}\to \qquad \cfrac {\ } {\Gamma, \tJ P, \tJ{P \to Q} \vdash \tJ Q} \text{AL}\to \end{array} \end{equation}

여기서 (컴퓨터 공학적으로는 그다지 중요하지 않은 \top\bot을 무시하면) 각 방법의 정확히 절반이 공리로 바뀌었다는 점에 유의하자. 이런 구성으로 인해 이 변형된 논건 대수를 "반(半)공리적 논건 대수"("Semi-Axiomatic Sequent Calculus", 줄여서 "SAX"[2])라고 부른다[3].

반공리적 논건 대수와 저수준(low-level) 자료 표현(data representation)

이 글에서 논건 대수의 변형인 반공리적 논건 대수를 소개한 당초의 이유는 논건 대수의 컴퓨터 공학적 해석, 즉 커리-하워드 대응을 찾기 위해서였다. 이제 커리-하워드 대응을 주기에 적합한 논건 대수의 변형을 끝마쳤으니 본격적으로 이 커리-하워드 대응을 설명할 것이다. 우선 각 판단들을 프로그램에서 쓸 수 있도록 표식을 붙이자. 1 편에서 다룬 자연 연역과 함수형 언어의 관계에서는 모든 가정에 변수 이름이라는 표식을 붙여 가정을 프로그램 내에서 쓸 수 있도록 했다. 논건 대수에서 사용할 표식은 단순한 이름과는 살짝 다른, "메모리 주소"("memory address")이다. 이 메모리 주소를 모든 가정과 귀결에 붙이도록 하자. 예를 들어 L\text{L}\land 규칙에 메모리 주소를 붙이면 다음의 규칙을 얻는다.

Γ,a.0:P true,a.1:Q trueb:R trueΓ,a:PQ trueb:R trueL \global\def\tJ#1{#1\ \texttt{true}} \begin{equation} \begin{array}{c} \cfrac {\Gamma, a.0{:} \tJ P, a.1{:} \tJ Q \vdash b{:} \tJ R} {\Gamma, a{:} \tJ{P \land Q} \vdash b{:} \tJ R} \text{L}\land \end{array} \end{equation}

여기서 전제의 가정 P trueP\ \texttt{true}Q trueQ\ \texttt{true}에 붙은 a.0a.0a.1a.1이라는 메모리 주소에 주목하자. 이 주소는 결론에 등장하는 aa라는 주소에 .0.0.1.1이라는 "접근자"("accessor")를 추가한 것이다. 이 대응에서 L\text{L}\land 규칙을 해석하는 방식을 통해 접근자의 의미를 이해해보자. L\text{L}\land 규칙의 해석은 다음과 같다.

PPQQ의 쌍(Pair) PQP \land Q를 저장하고 있는 메모리 주소 aa에서 PP를 저장하고 있는 메모리 주소 a.0a.0QQ를 저장하고 있는 메모리 주소 a.1a.1을 얻어내 이를 사용하는 규칙

이를 좀 더 구체화시켜 다음과 같은 메모리 도식을 그릴 수 있다. 아래 도식에서 연속된 사각칸은 연속된 메모리 영역을 뜻한다.

a mem1 ... a ... mem2 ... a.0 a.1 ... mem1:a->mem2:a0 mem3 ... v0 ... v1 ... mem2:a0->mem3:v0 mem2:a1->mem3:v1

이 도식이 말하는 것은 aa라는 주소에 .0.0이라는 접근자를 추가하면 메모리 주소 aa에 저장되어 있는 값을 주소로 쓰고, .1.1이라는 접근자를 추가하면 그 다음 주소를 사용한다는 것이다. 이는 쌍이 (가장) 직관적인 구조로 메모리에 저장되어있을 때 쌍의 각 구성원을 접근하는 방법에 대한 설명을 준다.

비슷한 방식으로 L\text{L}\lor에도 메모리 주소를 추가할 수 있다.

Γ,a.1:P trueb:R trueΓ,a.1:Q trueb:R trueΓ,a:PQ trueb:R trueL \global\def\tJ#1{#1\ \texttt{true}} \begin{equation} \begin{array}{c} \cfrac {\Gamma, a.1{:} \tJ P \vdash b{:} \tJ R \qquad \Gamma, a.1{:} \tJ Q \vdash b{:} \tJ R} {\Gamma, a{:} \tJ{P \lor Q} \vdash b{:} \tJ R} \text{L}\lor \end{array} \end{equation}

여기서는 전제의 가정에 등장하는 P trueP\ \texttt{true}Q trueQ\ \texttt{true} 모두 a.1a.1이라는 주소를 사용하고 있다. 이는 a.0a.0의 자리에 PQP \lor Q(PP 혹은 QQ)가 PP로부터 만들어졌는지 QQ로부터 만들어졌는지 구분하는 태그(tag)가 있기 때문이다. 예를 들어 PP로부터 PQP \lor Q를 만들었을 경우, a:PQ truea : P \lor Q\ \texttt{true}에 대한 메모리를 도식화하면 다음과 같다.

a mem1 ... a ... mem2 ... 0 a.1 ... mem1:a->mem2:a0 mem3 ... v ... mem2:a1->mem3:v

aa가 가리키고 있는 메모리 주소에는 00(PP로부터 만들어졌음을 뜻하는 태그)만이 들어있음에 유의하자. QQ로부터 PQP \lor Q를 만들었다고 한다면 00대신 11을 태그로 넣어 이를 표시할 수 있다. (PPQQ에 대응되는) 실제 값은 메모리 주소 a.1a.1에 저장되어 있다. 이 또한 태그된 합 자료형(Tagged sum type)을 나타내는 가장 직관적인 방법에 대한 설명이다.

그렇다면 귀결의 위치에는 왜 메모리 주소를 붙였을까? 위의 규칙에서 메모리 주소 bb에 대해서는 특별한 설명을 하지 않아 이 메모리 주소가 쓸모가 없어 보일 수 있다. 이 메모리 주소의 유용성을 설명하기 위 \land\lor의 나머지 규칙, 즉 AR\text{AR} 규칙에 대해, 특히 AR\text{AR}\land 규칙에 대해 살펴보자.

 Γ,a:P true,b:Q truec:PQ trueAR \global\def\tJ#1{#1\ \texttt{true}} \begin{equation} \begin{array}{c} \cfrac {\ } {\Gamma, a{:} \tJ P, b{:}\tJ Q \vdash c{:} \tJ{P \land Q}} \text{AR}\land \end{array} \end{equation}

메모리의 관점에서 설명하자면 이 규칙은

PP값을 가진 주소 aaQQ값을 가진 주소 bb가 있다면 PQP \land Q 값을 가진 주소 cc에 값을 채워넣을 수 있다

는 규칙이라고 볼 수 있다. 이 규칙의 결과를 메모리 도식으로 그려보면 다음과 같다.

a mem1 ... a ... b ... c ... mem2 ... c.0 c.1 ... mem1:c->mem2:c0 mem3 ... v0 ... v1 ... mem1:a->mem3:v0 mem1:b->mem3:v1 mem2:c0->mem3:v0 mem2:c1->mem3:v1

즉, 주소 aabbc.0c.0c.1c.1에 복사하는 것이라고 볼 수 있다. 마찬가지로 AR1\text{AR}\lor_1AR2\text{AR}\lor_2 또한 가정의 주소와 적절한 태그를 귀결의 메모리 주소가 가리키는 메모리에 복사해 넣는 것이라고 볼 수 있다.

지금까지는 가정과 귀결에 주소를 붙이고 이 주소가 어떻게 쓰이는지 이해하는데 초점을 맞췄다. 이제 이 이해를 바탕으로 증명에 해당하는 항을 써 보자. 자연 연역의 항과 귀결은 ::을 구분자로 사용하였지만, 반공리적 논건 대수의 경우 귀결의 자리에 "주소 : 진리 판단" 꼴이 이미 쓰이고 있다. 따라서 항과 귀결을 구분하기 위해 ::를 사용하는 대신 \dblcolon을 사용할 것이다. 항을 포함한 완전한 AR\text{AR}\land 규칙은 다음과 같다.

 Γ,a:P true,b:Q truec(a,b)c:PQ trueAR \global\def\tJ#1{#1\ \texttt{true}} \begin{equation} \begin{array}{c} \cfrac {\ } {\Gamma, a{:} \tJ P, b{:}\tJ Q \vdash c \colonequals (a, b) \dblcolon c{:} \tJ{P \land Q}} \text{AR}\land \end{array} \end{equation}

여기서 xvx \colonequals v는 값 vv를 주소 xx가 가리키는 메모리에 써넣는다는 뜻이다. 즉 이 규칙은 주소 aabb를 쌍으로 묶어서 이를 주소 xx가 가리키는 메모리에 써넣는 규칙이 된다. 이와 비슷하게 AR1\text{AR}\lor_1AR2\text{AR}\lor_2에는 다음의 항을 줄 수 있다.

 Γ,a:P trueb(0,a)b:PQ trueAR1 Γ,a:Q trueb(1,a)b:PQ trueAR1 \global\def\tJ#1{#1\ \texttt{true}} \begin{equation} \begin{array}{c} \cfrac {\ } {\Gamma, a{:} \tJ P \vdash b \colonequals (0, a) \dblcolon b{:} \tJ{P \lor Q}} \text{AR}\lor_1 \qquad \cfrac {\ } {\Gamma, a{:} \tJ Q \vdash b \colonequals (1, a) \dblcolon b{:} \tJ{P \lor Q}} \text{AR}\lor_1 \end{array} \end{equation}

L\text{L} 규칙도 앞서의 메모리에 대한 이해를 바탕으로 "메모리의 값을 읽어 작업을 한다"는 항을 줄 수 있다. 예를 들어 L\text{L}\land의 완전한 규칙은 다음과 같다.

Γ,a.0:P true,a.1:Q trueMb:R trueΓ,a:PQ trueread a as (,)Mb:R trueL \global\def\tJ#1{#1\ \texttt{true}} \begin{equation} \begin{array}{c} \cfrac {\Gamma, a.0{:} \tJ P, a.1{:} \tJ Q \vdash M \dblcolon b{:} \tJ R} {\Gamma, a{:} \tJ{P \land Q} \vdash \text{read}\ a\ \text{as}\ ({,}) \Rightarrow M \dblcolon b{:} \tJ R} \text{L}\land \end{array} \end{equation}

즉, MMa.0a.0a.1a.1을 사용해서 bbRR 형의 값을 써넣는다면, read a as (,)M\text{read}\ a\ \text{as}\ ({,}) \Rightarrow Maa를 사용해서 bb에 같은 값을 써넣는 프로그램이 된다. L\text{L}\lor의 완전한 규칙 역시 같은 구조를 설명한다.

Γ,a.1:P trueM0b:R trueΓ,a.1:Q trueM1b:R trueΓ,a:PQ trueread a as (0,)M0  (1,)M1b:R trueL \global\def\tJ#1{#1\ \texttt{true}} \begin{equation} \begin{array}{c} \cfrac {\Gamma, a.1{:} \tJ P \vdash M_0 \dblcolon b{:} \tJ R \qquad \Gamma, a.1{:} \tJ Q \vdash M_1 \dblcolon b{:} \tJ R} {\Gamma, a{:} \tJ{P \lor Q} \vdash \text{read}\ a\ \text{as}\ (0{,}) \Rightarrow M_0\ |\ (1{,}) \Rightarrow M_1 \dblcolon b{:} \tJ R} \text{L}\land \end{array} \end{equation}

M0M_0a.1:P truea.1{:}P\ \texttt{true}를 사용해서 bb의 값을 채우고, 마찬가지로 M1M_1a.1:Q truea.1{:}Q\ \texttt{true}를 사용해서 bb의 값을 채운다면 read a as (0,)M0  (1,)M1\text{read}\ a\ \text{as}\ (0{,}) \Rightarrow M_0\ |\ (1{,}) \Rightarrow M_1aa를 사용해서 bb의 값을 채울 수 있는 프로그램이 된다.

이제 양의 방법(\land\lor)을 어떻게 이해해야하는지 모두 살펴봤으니, 음의 방법(\to)은 어떻게 이해해야하는지 살펴보도록 하자. 우선 R\text{R}\to를 보자.

Γ,a:P trueMb:Q trueΓc((a,b)M)c:PQ trueR \global\def\tJ#1{#1\ \texttt{true}} \begin{equation} \begin{array}{c} \cfrac {\Gamma, a{:} \tJ P \vdash M \dblcolon b{:} \tJ Q} {\Gamma \vdash c \colonequals ((a, b) \Rightarrow M) \dblcolon c{:} \tJ{P \to Q}} \text{R}\to \end{array} \end{equation}

이 규칙은 주어진 메모리 주소 aa에서 값을 읽어 주어진 메모리 주소 bb에 결과를 쓰는 MM라는 프로그램이 주어졌을 때, 임의의 두 메모리 주소 aa, bb에 대한 프로그램 MM이 우리 PQP \to Q를 위한 메모리 주소 cc에 쓸 값이라는 규칙이다. 컴퓨터의 관점에서 이는 인자의 주소(aa)와 반환 값의 주소(bb)가 주어졌을 때 인자를 사용해 반환값을 채워넣는 프로그램이 바로 함수라는 이야기이다. 나머지 규칙인 AL\text{AL}\to는 이렇게 저장된 함수를 "읽는" 규칙이다.

 Γ,a:P true,b:PQ trueread b with (a,c)c:Q trueAL \global\def\tJ#1{#1\ \texttt{true}} \begin{equation} \begin{array}{c} \cfrac {\ } {\Gamma, a{:} \tJ P, b{:} \tJ{P \to Q} \vdash \text{read}\ b\ \text{with}\ (a, c) \dblcolon c{:} \tJ Q} \text{AL}\to \end{array} \end{equation}

이는 인자의 주소 aa와 반환값을 저장할 주소 cc가 주어졌으니, 이들을 사용해 bb가 가지고 있는 "인자를 사용해 반환값을 채워넣는 프로그램"을 실행하라는 규칙이다.

지금까지 AR\text{AR} 혹은 R\text{R} 규칙이 어떤 메모리 주소에 값을 써넣는 규칙이고 AL\text{AL} 혹은 L\text{L} 규칙이 어떤 메모리 주소에서 값을 읽어내는 규칙임을 살펴보았다. 그렇다면 init\text{init}cut\text{cut} 규칙은 무슨 역할을 할까? 우선 init\text{init} 규칙에 주소를 추가해보도록 하자.

a:P trueΓΓb:P trueinit \global\def\tJ#1{#1\ \texttt{true}} \begin{equation} \begin{array}{c} \cfrac {a{:}\tJ P \in \Gamma} {\Gamma \vdash b{:} \tJ P} \text{init} \end{array} \end{equation}

PP의 값을 가진 메모리 주소 aa가 있고, PP의 값을 써넣어야 하는 메모리 주소 bb가 있다. 무엇을 할 수 있을까? 메모리 aa의 값을 복사해 넣을 수 있다! 따라서 다음과 같은 이름을 항에 붙일 수 있다.

a:P trueΓΓcopy a into bb:P trueinit \global\def\tJ#1{#1\ \texttt{true}} \begin{equation} \begin{array}{c} \cfrac {a{:}\tJ P \in \Gamma} {\Gamma \vdash \text{copy}\ a\ \text{into}\ b \dblcolon b{:} \tJ P} \text{init} \end{array} \end{equation}

cut\text{cut} 역시 중요한 역할을 맡는다. 이는 지금까지의 논의에서 빠져 있었던 "메모리 주소를 얻는 방법"을 주기 때문이다. 완전한 cut\text{cut} 규칙은 다음과 같다.

ΓMa:P trueΓ,a:P trueNb:Q trueΓalloc a by M in Nb:Q truecut \global\def\tJ#1{#1\ \texttt{true}} \begin{equation} \begin{array}{c} \cfrac {\Gamma \vdash M \dblcolon a{:} \tJ P \qquad \Gamma, a{:} \tJ P \vdash N \dblcolon b{:} \tJ Q} {\Gamma \vdash \text{alloc}\ a\ \text{by}\ M\ \text{in}\ N \dblcolon b{:} \tJ Q} \text{cut} \end{array} \end{equation}

즉, cut\text{cut}PP의 값을 위한 메모리 aa를 할당(allocate)하고, MM을 통해 aa를 초기화한 뒤 NN을 실행하는 규칙이라고 볼 수 있다.

지금까지 다룬 규칙을 포함해 반공리적 논건 대수의 모든 규칙을 항과 함께 쓰면 다음과 같다.

a:P trueΓΓcopy a into bb:P trueinitΓMa:P trueΓ,a:P trueNb:Q trueΓalloc a by M in Nb:Q truecut Γa()a: trueR Γ,a: trueread ab:P trueL Γ,a:P true,b:Q truec(a,b)c:PQ trueARΓ,a.0:P true,a.1:Q trueMb:R trueΓ,a:PQ trueread a as (,)Mb:R trueL Γ,a:P trueb(0,a)b:PQ trueAR1 Γ,a:Q trueb(1,a)b:PQ trueAR2Γ,a.1:P trueb:R trueΓ,a.1:Q trueb:R trueΓ,a:PQ trueb:R trueLΓ,a:P trueMb:Q trueΓc((a,b)M)c:PQ trueR Γ,a:P true,b:PQ trueread b with (a,c)c:Q trueAL \global\def\tJ#1{#1\ \texttt{true}} \begin{equation} \begin{array}{c} \cfrac {a{:}\tJ P \in \Gamma} {\Gamma \vdash \text{copy}\ a\ \text{into}\ b \dblcolon b{:} \tJ P} \text{init} \newline\newline \cfrac {\Gamma \vdash M \dblcolon a{:} \tJ P \qquad \Gamma, a{:} \tJ P \vdash N \dblcolon b{:} \tJ Q} {\Gamma \vdash \text{alloc}\ a\ \text{by}\ M\ \text{in}\ N \dblcolon b{:} \tJ Q} \text{cut} \newline\newline\newline \cfrac {\ } {\Gamma \vdash a \colonequals () \dblcolon a{:} \tJ \top} \text{R}\top \qquad \cfrac {\ } {\Gamma, a{:}\tJ \bot \vdash \text{read}\ a \dblcolon b{:} \tJ P} \text{L}\bot \newline\newline\newline \cfrac {\ } {\Gamma, a{:}\tJ P, b{:}\tJ Q \vdash c \colonequals (a, b) \dblcolon c{:}\tJ{P \land Q}} \text{AR}\land \newline\newline \cfrac {\Gamma, a.0{:}\tJ P, a.1{:}\tJ Q \vdash M \dblcolon b{:}\tJ R} {\Gamma, a{:}\tJ{P \land Q} \vdash \text{read}\ a\ \text{as}\ (,) \Rightarrow M \dblcolon b{:}\tJ R} \text{L}\land \newline\newline\newline \cfrac {\ } {\Gamma, a{:}\tJ P \vdash b \colonequals (0, a) \dblcolon b{:}\tJ{P \lor Q}} \text{AR}\lor_1 \newline\newline \cfrac {\ } {\Gamma, a{:}\tJ Q \vdash b \colonequals (1, a) \dblcolon b{:}\tJ{P \lor Q}} \text{AR}\lor_2 \newline\newline \cfrac {\Gamma, a.1{:}\tJ P \vdash b{:}\tJ R \qquad \Gamma, a.1{:}\tJ Q \vdash b{:}\tJ R} {\Gamma, a{:}\tJ{P \lor Q} \vdash b{:}\tJ R} \text{L}\lor \newline\newline\newline \cfrac {\Gamma, a{:}\tJ P \vdash M \dblcolon b{:}\tJ Q} {\Gamma \vdash c \colonequals ((a, b) \Rightarrow M) \dblcolon c{:}\tJ{P \to Q}} \text{R}\to \newline\newline \cfrac {\ } {\Gamma, a{:}\tJ P, b{:}\tJ{P \to Q} \vdash \text{read}\ b\ \text{with}\ (a, c) \dblcolon c{:}\tJ Q} \text{AL}\to \end{array} \end{equation}

양의 방법과 음의 방법의 차이

앞에서 양의 방법과 음의 방법이 직관적인 차이를 가진다고 설명했다. 이제 반공리적 논건대수의 컴퓨터 공학적 해석을 설명했으니 이 직관적인 차이를 보다 구체적으로 설명해보자. 양의 방법의 경우 L\text{L} 규칙이 메모리에 저장된 모든 자료를 읽어낼 수 있다. 다시 말해 a.1a.1 등의 주소를 통해 주소 aa에 저장된 자료의 상세를 알아낼 수 있다. 반면에 음의 방법의 경우 AL\text{AL} 규칙이 메모리에 저장된 모든 자료를 읽어낼 수 없다. \toAL\text{AL} 규칙은 인자의 메모리와 반환값의 메모리가 주어졌을 때 주어진 인자에 해당하는 반환값만을 읽어낼 수 있고, 메모리 안에 저장된 자료의 상세는 알아낼 수 없다. 이를 다른 방식으로는 다음과 같이 표현하고는 한다.

  • 양의 방법은 모든 상세를 읽어낼 수 있다.
  • 음의 방법은 원하는 상세를 관찰할 수 있다.

마치며

1 편에 이어서 논리적 증명을 컴퓨터 공학적으로 해석하는 방법에 대해 알아보았다. 이 글에서는 특히 논건 대수와 메모리 수준의 자료 표현의 관계를 커리-하워드 대응의 관점에서 살펴보았다. 이 관계를 명확히 하기 위해 사용된 변형된 논건 대수인 반공리적 논건대수는 프랭크 페닝(Frank Pfenning) 교수님[4]의 최근(2020년) 연구물이자 현재에도 활발하게 연구가 진행 중인 체계이다[5]. 이 체계의 다른 응용 중 하나를 언급하는 것으로 이 체계의 유용성을 강조하며 글을 마치도록 하겠다. 이는 함수형 언어를 저수준으로 컴파일(Compile)하는 것으로, 자연 연역(함수형 언어에 대응되는 체계)을 반공리적 논건 대수(저수준 자료 표현 체계)로 변환하는 논리적 변환이 컴파일에 그대로 대응될 수 있다는 점을 이용한다. 이 컴파일 과정 역시 ML(Meta Language[6])계열의 언어를 컴파일하는데 응용하기 위해 연구가 진행 중이다. 이 두 편의 글이 논리와 컴퓨터 공학의 관계를 개발자들이 이해하는데에 도움을 주었기를 바라며 이만 줄이도록 하겠다.


  1. 엄밀히 말한다면 ΓQ true\Gamma \vdash Q\ \texttt{true}를 바로 사용할 수는 없고, "논리적 약화"라고 불리는 것을 증명해서 ΓQ true\Gamma \vdash Q\ \texttt{true}라면 Γ,P trueQ true\Gamma, P\ \texttt{true} \vdash Q\ \texttt{true}임을 보인 뒤에 Γ,P trueQ true\Gamma, P\ \texttt{true} \vdash Q\ \texttt{true}를 대신 사용해야만 한다. 여기에서는 글의 번잡함을 피하기 위해 가정이 서로 다른 두 가정적 판단 사이에서도 cut\text{cut} 규칙을 사용 가능한 것으로 놓고 증명을 구성하였다. ↩︎

  2. 원 저자는 이를 /sɒks/(양말의 "Socks"와 같은 발음)라고 발음한다. ↩︎

  3. 여기의 "반"이 반대를 뜻하는 것이 아니라 절반을 뜻하는 것임을 다시 강조하고자 한다. 이 이름 자체가 절의 규칙이 공리인 이 변형 논건 대수의 특징을 설명하고 있다. ↩︎

  4. 람다 대수(λ\lambda-Calculus)를 처음 만들어 낸 알론조 처치(Alonzo Church) 교수님의 제자의 제자("학문적 손자"라고도 한다)이시며 현대의 북미의 컴퓨터 공학과 논리에 지대한 영향을 끼치고 계신 교수님이시다. ↩︎

  5. 예를 들어 기본적인 반공리적 논건 대수의 반복되는 참조를 개선한 체계인 SNAX(Semi-Axiomatic Sequent Calculus with Snip, 2023년) 등의 연구가 계속 이어지고 있다. ↩︎

  6. Machine Learning 언어가 아니다! ↩︎

12

No comments

If you have a fediverse account, you can comment on this article from your own instance. Search https://hackers.pub/ap/articles/0196a220-14ea-7491-9b5f-6f49ecfb1b0a on your instance and reply to it.