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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
|
# 027 — 계산의 핵: 상태는 값 하나, 값은 몇 가지로 짓는다
작성일: 2026-10-13. 상태: 설계와 단계. [026](026-app-contract.md)이 얼릴 계약 안에서 계산의 언어를 다시 세운다. 잴 도구는
[140](../research/140-spec-suite.md)의 명세 묶음이다. 1.0 전이라 호환은 챙기지 않는다. 사용자의 말: "진행해" (2026-10-13).
1단계를 만들었다([140](../research/140-spec-suite.md)의 뒷절).
- aup로 쓴 SHA-256이 공식 벡터를 세 실행 길에서 모두 지난다.
- 줄 수는 막대에 못 미쳤다(aup 52 대 파이썬 28). 남은 차이는 형식 지정, 바이트 잇기와 자르기, 값으로서의 리스트다. 이것들을 2단계에 더했다.
- 시간은 C의 176배, 순수 파이썬의 0.43배다.
## 쉬운 말로
- **지금의 꼴.** aup와 Pure는 패턴마다 종류와 명령을 둔다. 커서, 인덱스, 문서, 표 보기, 메시지의 행이 각각 따로다. 그래서 세상의
명세를 담지 못하고(140), 새 패턴마다 형식과 세 실행 길이 함께 자란다.
- **이 설계의 꼴.** 그것을 "값 몇 가지와, 그 값들이 서로를 담는 법"으로 바꾼다.
- 상태는 타입 있는 값 하나다.
- 값은 수(정수, 실수, bool), 바이트(text는 UTF-8인 바이트), 레코드, 갈래, 리스트(키가 있으면 맵)다.
- **계산.** 함수(재귀 포함)와 접기다. 끝남은 문법이 아니라 예산이 보증한다. 이더리움의 가스와 같은 생각이다. 가스가 다하면 그
호출의 상태 변경이 모두 되돌아가는데, 이것이 026의 원자성과 같다.
- **빠름.** 뜻이 아니라 구현에서 온다. 열로 담기, B+트리, 묶음 실행, 같은 답일 때만 차례 바꾸기가 그 수단이다.
- **단계.** 다섯이다.
- 1단계(바이트, 비트, 수의 리스트)로 SHA-256을 쓴다.
- 2단계(중첩, 갈래, 재귀, 글자)로 JSON을 쓴다.
- 3단계에서 중첩된 상태를 저장한다.
- 4단계에서 패턴을 모은다.
- 5단계에서 수의 모델을 정한다.
- **근거.**
- 140의 탐침
- 지금의 구현: 값의 칸 `Slot`, 열로 담은 B+트리 `PureList`, aup의 타입 여덟
- 선행 기술: 아래 "선행" 절
- **다음 결정.** 1단계를 만든다.
## 핵
### 값
| 값 | 뜻 | 지금 | 바뀌는 것 |
|---|---|---|---|
| `bool` | 참, 거짓 | 같음 | — |
| `i64` | 정확한 정수, −2^63 … 2^63−1, 넘치면 `overflow` | 같음 | 비트 연산(1단계). 이름과 리터럴의 기본은 5단계 |
| `number` | 유한한 binary64 | 같음 | 5단계(수의 모델) |
| `bytes` | 바이트의 열, 불변 | 길이와 text 변환뿐 | 자리로 읽기, 자르기, 잇기, 짓기(1단계) |
| `text` | UTF-8로 검사한 바이트 | 같은 표현 | 글자로 읽기는 그 위의 견해(2단계) |
| 레코드 | 이름 있는 필드의 곱 | 필드는 수, text, bool, i64 | 필드에 아무 값(2단계) |
| 갈래 | 태그 붙은 경우의 합 | 없음 | 새로. `match`가 모든 경우를 다룬다(2단계) |
| `list of T [by k]` | 차례 있는 열. `by k`면 k의 차례이고 키마다 하나다 | 레코드만, 상태와 이벤트와 메시지의 행으로 따로 | 아무 T(1단계 수, 2단계 전부). 키 없는 리스트의 키는 자리다 |
| 앵커 | 편집을 따라가는 위치 | 커서와 인덱스(상태의 종류 둘) | 하나로(4단계) |
### 계산
- **그대로 두는 것.** 식, `let`, `if`, `for`(세기와 걷기), `break`.
- **함수.**
- 자신을 부를 수 있다(2단계).
- 인라인은 구현의 선택이다. 작은 fn은 지금처럼 인라인하고, 재귀하는 fn은 부른다.
- 매개변수에 타입을 적지 않는 것은 그대로다. 부르는 타입마다 한 벌을 만든다(단형화).
- **`match`.** 갈래의 모든 경우를 다룬다. 빠진 경우는 컴파일 오류다(2단계).
- **끝을 모르는 반복.** `while`을 둔다(2단계). 세기의 상한은 뜻에서 필요하지 않다. 묶음 실행이 시작할 때의 횟수를 쓰는 것은 구현이
상한을 알아볼 수 있을 때다.
- **접기.** 뜻은 차례대로의 왼쪽 접기다. 구현은 같은 답과 같은 실패를 낼 때만 차례를 바꾼다. 묶음 실행기의 차례 없는 모으기가 이미
이 규칙을 따른다.
- **비트 연산.** 정수를 무한한 2의 보수로 보고 정한다. 파이썬의 정수와 같은 뜻이다.
- `&`, `|`, `^`, `~`: 비트마다의 연산이다.
- `x << n`은 x·2^n이다. i64를 넘으면 `overflow`다.
- `x >> n`은 floor(x / 2^n)이다.
- n은 0부터 63까지다. 밖이면 `limit`이다.
- 어느 기계에서나 같은 뜻이고, C의 정의되지 않은 동작이 없다.
- **끝남과 결정성.**
- 모든 걸음은 실행량을 쓰고, 부름의 깊이는 프레임의 바이트로 메모리 몫에 센다. 넘으면 `work`나 `memory`로 끝나고, 이벤트는
통째로 되돌아간다.
- 결정성의 단위는 모듈이다. 같은 모듈과 같은 이벤트열이면 실패의 자리까지 같다.
- 소스는 컴파일러의 판에 묶인다. EVM의 바이트코드와 가스표가 그렇다. 이것이 026의 의심 6(예산의 단위)에 대한 답이다.
### 효과
026 그대로다. 상태에 쓰기, 보내기, 답하기, `require`.
### 상태는 값 하나
- 앱의 상태는 레코드 값 하나다. 선언한 상태들이 그 필드이고, 수명(저장, transient)은 필드의 성질이다.
- 저장은 바뀐 부분만 쓴다. 지금 리스트가 이미지와 로그로 하는 그대로다. 중첩된 리스트도 제 이미지와 로그를 가진다(경로로 이름을
붙인다, 3단계).
- 값은 불변이라 스냅숏은 나누기만 한다. 지금 리스트의 공유 사본이 그 구현이다.
### 뜻과 표현
| 뜻 | 표현(구현이 고른다) |
|---|---|
| 레코드의 리스트 | 열로 담은 B+트리, 값만큼 좁힌 열, HASHED(지금) |
| 수의 리스트 | 필드 하나인 레코드의 리스트(1단계), 나중에 배열 |
| 바이트 짓기(`out = out + byte(x)`의 반복) | 왼쪽이 이벤트 공간의 끝에 있으면 제자리 덧붙이기 |
| 표 보기 | 물을 때 칸 계산 |
| 접기 | 묶음 실행, 차례 없는 모으기(같은 답일 때만) |
| 작은 fn | 인라인 |
## 026의 의심에 대한 답
| 의심 | 답 | 단계 |
|---|---|---|
| 1. 입력의 종류 | 입력은 메시지 하나다. 키, 글자, 틱은 표면과 호스트가 만드는 메시지다 | 4 |
| 2. 보기의 종류 | 보기는 아무 값을 낸다 | 4 |
| 3. 커서와 인덱스 | 앵커 하나로 모은다. 다만 키가 있는 리스트에서 인덱스는 키와 같을 수 있다. 4단계에서 앵커가 text에만 필요한지 본다 | 4 |
| 4. 키별 문서 | 없앤다. 키 있는 리스트가 한다 | 4 |
| 5. 수의 모델 | 정할 것: 정수 리터럴의 기본, `/`와 `//`, 돈을 위한 십진수 | 5 |
| 6. 예산의 단위 | 모듈로 정한다(위) | 이 문서 |
| 7. 고정 한도 | 뜻에는 예산(실행량, 메모리)과 모듈의 크기만 남긴다. 상태 32, 입력 32, 레코드 16, 필드 16, 컬렉션 1, 중첩 8, aup 소스 32 KB는 뺀다 | 4 |
| 8. 교체의 세부 | 수의 모델 뒤에 다시 본다 | 5 |
| 9. 메시지의 행 | 메시지의 필드가 아무 값을 가지면 따로 둘 까닭이 없다 | 2 |
## 단계
### 1단계: 바이트, 비트, 수의 리스트 (SHA-256)
- **Pure.**
- 바이트를 자리로 읽기(`b[i]` → i64, 밖이면 `limit`), 자르기, 잇기, 한 바이트로 짓기
- i64의 비트 연산 여섯
- 이벤트의 지역 칸이 바이트를 담는다
- **aup.**
- `b[i]`, `b[a .. c]`, `b + c`, `byte(n)`
- i64의 `& | ^ ~ << >>`, 16진 리터럴 `0x…`
- `list of i64`와 `list of number`(안에서는 필드 하나인 레코드), 리스트 리터럴 `[ … ]`
- 키 없는 리스트를 자리로 읽고 쓰기 `xs[i]`
- **막대.**
- aup로 쓴 SHA-256이 NIST의 짧은 메시지 벡터와 긴 메시지 벡터를 모두 지난다(Pure의 검사 안에서).
- 줄 수가 같은 일을 하는 파이썬 참조 이하다.
- C 대비 시간은 재고 기록하되 막대는 두지 않는다. 바이트와 비트의 일은 실행기로 돈다. 빠르게 하는 것은 핵이 선 뒤다.
- 실행기만의 길에서 다섯 일(041)의 명령 수가 ±0.1%, 은행 질의의 명령 수가 ±1% 안이다. 새 명령은 기존 길을 바꾸지 않는다.
- **검증.** 새 명령마다 경계(밖의 자리, 음수 시프트, 넘침)를 단위 시험으로 본다. 무작위 입력의 다이제스트는 파이썬 `hashlib`와 같아야
한다.
### 2단계: 중첩, 갈래, 재귀, 글자 (JSON)
크기 때문에 셋으로 나눈다(2026-10-13). 각각 재는 일이 있다.
- **2a(만듦):** 형식 지정, 바이트 잇기와 자르기, 바이트와 text를 담는 `let`, `while`, `&&`와 `||`의 단락 평가. JSON을 받거나
거절하는 검사기로 잰다. 결과는 [140](../research/140-spec-suite.md)의 2a절이다.
- JSONTestSuite에서 틀린 것이 없다.
- 줄 수는 파이썬 이하다(80 대 90).
- 시간은 C의 116배, 파이썬의 1.2배다.
- 쓰다가 드러난 뜻의 틈 하나를 메웠다. `&&`가 양쪽을 다 계산해서 `i < n && d[i]`가 실패했다. 이제 단락 평가이고, 오른쪽이
실패할 수 없을 때는 지금처럼 AND 하나를 낸다. 그래서 TPC-C를 포함한 기존 모듈 35개가 바이트까지 같다.
- **2b:** 중첩(레코드 안의 레코드와 리스트), 갈래와 `match`, 값으로서의 리스트, 메시지 필드의 아무 값. JSON을 트리로 읽고 묻는다.
- **2c:** 재귀(부르기와 돌아가기, 함수마다의 검증), 글자로 읽기.
- 레코드의 필드와 리스트의 원소가 아무 값을 가진다.
- 갈래와 `match`를 둔다.
- 재귀하는 fn과 `while`을 둔다. Pure에는 부르기와 돌아가기, 함수마다의 검증이 생긴다.
- `for c in t`로 글자(코드 포인트)를 읽는다.
- 메시지의 필드가 아무 값을 가진다. JSON의 배열과 객체가 곧 리스트와 레코드다.
- 1단계의 SHA-256이 길었던 까닭을 여기서 푼다.
- 형식 지정(`{x:08x}`, `{price:.2}`)
- 바이트 값을 잇고 자르기(`b + c`, `b[a .. c]`)와 바이트를 담는 `let`
- 값으로서의 리스트: 블록 안에서 짓고 다시 짓는다
- fn을 펼칠 때 리터럴 인자를 접기: 구현의 일이다. 140이 블록당 명령의 39%를 fn 호출의 몫으로 쟀다
- 먼저 이벤트와 보기의 값(메모리 안)에서 한다. 상태는 3단계다.
- **막대.**
- JSON 파서가 JSONTestSuite의 `y_`를 모두 받고 `n_`을 모두 거절한다. `i_`는 정한 쪽을 적는다.
- 줄 수가 파이썬 참조 이하다.
- 시간을 기록한다.
- TPC-C와 은행 질의가 그대로다(026의 중단 기준).
### 3단계: 중첩된 상태의 저장
- 중첩된 리스트의 이미지와 로그를 경로로 이름 붙인다.
- 스냅숏의 나누기와 교체의 이름 잇기가 깊이에서도 그대로 성립해야 한다.
- **막대.** 메모리 앱과 수시로 재시작하는 저장 앱이 매 단계 비트까지 같다(지금의 대조를 중첩으로 넓힌다). 커밋의 모든 단계에서
죽여도 전부 아니면 없음이다.
### 4단계: 패턴 모으기
- 앵커, 메시지 하나인 입력, 아무 값인 보기를 둔다.
- 키별 문서와 고정 한도를 없애고, 메시지의 행을 중첩으로 옮긴다.
- **막대.**
- Pure, aup, Vega의 모든 검사를 옮긴 뒤 초록이다.
- 명령과 상태 종류의 수, 코어의 줄 수가 줄었다(세어 적는다).
- TPC-C와 은행 질의가 그대로다.
### 5단계: 수의 모델
- 정수 리터럴의 기본, `/`와 `//`, 돈의 십진수, 묶음 실행기의 2^53 검사를 정한다.
- **막대.** TPC-C가 SQLite와 행마다 같은 상태를 남기는 것이 그대로다.
**순서의 까닭.**
- 1과 2가 묶음의 명세 대부분을 연다. 가장 값이 크다.
- 3은 중첩을 상태까지 넓힌다.
- 4는 쌓인 것을 줄인다. 2 뒤에 해야 모을 곳(중첩, 갈래)이 생긴다.
- 5는 모든 앱의 수를 건드리므로 마지막이다.
## 선행
- **EVM의 가스.** 끝없는 반복과 재귀를 허락하고, 끝남과 결정성을 가스로 얻는다. 가스가 다하면 그 호출의 상태 변경이 되돌아간다. 가스는
명령마다 명세의 표로 정한다. 모든 노드가 같은 가스를 센다. Pure의 예산, 원자성, "모듈이 단위"와 같은 꼴이다.
- **파이썬의 정수 비트 연산.** 무한한 2의 보수 위의 뜻이다. Pure는 i64 안에서 같은 뜻을 쓰고, 넘으면 실패한다.
- **Elm.** 모델, 업데이트, 뷰와 레코드, 커스텀 타입(갈래)이다. aup 앱의 모양과 같다. 영속, 트랜잭션, 전달은 없다.
- **영속 자료 구조**(Clojure의 벡터와 맵). 구조를 나눠 스냅숏을 싸게 한다. Pure의 공유 리스트 사본이 그 한 예다(B+트리).
## 의심 (이 설계 안의)
- **바이트와 text를 따로 둘 것인가?** 표현은 하나이고 타입만 둘이다. 불변식(UTF-8)이 보기와 경계에 필요해서 타입은 남긴다.
- **앵커가 필요한가?** 항목에 키가 있으면 인덱스는 키다. text의 커서는 편집에 따라 옮겨야 하므로 남는다. 4단계에서 정한다.
- **`number`(binary64)는 앱 런타임에 필요한가?** 물리와 그래픽에는 필요하다. 돈에는 맞지 않는다(5단계).
- **세는 `for`가 필요한가?** 뜻으로는 `while`과 예산이면 된다. 다만 세기는 읽기 쉽고, 상한을 구현에 알려 준다. 남긴다.
## 1단계의 착수 기준
- **바꿀 결정.** 바이트, 비트, 수의 리스트로 SHA-256을 얇게 쓸 수 있으면 받아들이고, 2단계로 간다.
- **남은 질문.**
- 새 명령이 실행기, 묶음 실행기, JIT의 기존 길을 바꾸지 않는가?
- 한 블록에 드는 명령 수와 시간은 얼마인가?
- **최소 확인.** aup로 쓴 SHA-256, NIST 벡터, 파이썬 참조의 줄 수, C 대비 시간, 다섯 일과 은행 질의의 명령 수.
- **중단 기준.** 기존 일의 명령 수가 막대를 넘으면 멈추고, 새 명령이 기존 길을 건드린 곳을 찾는다. SHA-256이 파이썬보다 길면, 무엇이
길게 했는지 적고 그것을 1단계에서 고칠지 정한다.
|