aboutsummaryrefslogtreecommitdiffstats
path: root/docs/design/008-module-format.md
diff options
context:
space:
mode:
authoreunhhu <[email protected]>2026-09-28 05:14:16 +0100
committereunhhu <[email protected]>2026-09-28 05:14:16 +0100
commit468ddde46c7904ae14e29444351a738de73f8864 (patch)
tree3367ff0137ef609204e67c67c54198fd19ba1a0c /docs/design/008-module-format.md
parent15f0114d6a7da0a4f63028db12cac62c5f9cc922 (diff)
downloadpure-468ddde46c7904ae14e29444351a738de73f8864.tar.gz
pure-468ddde46c7904ae14e29444351a738de73f8864.zip
Read only the keys a test allows, and count distinct values
A filter, a fold or a walk's where (a test at the start of its block and a jump to its end when it fails) that ANDs comparisons of a keyed list's key with values reading no item gets a range at load (PureRange: a lower bound GT or GE, an upper LT or LE, EQ both). When it runs, the bounds are found once and looked up by key, and only the leaves between the two positions are read: O(log n + k) where it read every item. A filter leaves the items out of range out anyway, so it always may; a fold or a walk only when the rest of its test and its value cannot fault (no division, sum or product that may overflow, key or item that may be missing), since the items it skips would have run them; a walk's bounds must also read no state, local or list its block writes, as the where reads them anew for every item. A bound that faults leaves the test to run for every item, as written. A fold of kind 5 (distinct) counts the different values its included items give (-0 as 0), with a set per fold; it runs a leaf at a time and is never shaped. max, min and first alone fault over no item. ranges checks, against the same module reading every item, over 60 lists of up to 400 keyed items and 3,600 views: a count between two bounds, a sum between a lower and an upper bound with another condition, first equal to a key, min with the bound on the right, a count whose test may fault (no range), a filtered table in bounds, 359 walks changing and removing the items in bounds, and a walk whose body moves its bound (no range). lane_folds now makes distinct folds too.
Diffstat (limited to 'docs/design/008-module-format.md')
-rw-r--r--docs/design/008-module-format.md9
1 files changed, 8 insertions, 1 deletions
diff --git a/docs/design/008-module-format.md b/docs/design/008-module-format.md
index 7fb8641..dbac460 100644
--- a/docs/design/008-module-format.md
+++ b/docs/design/008-module-format.md
@@ -99,7 +99,7 @@ v5에는 뒤에 집계(FOLD), 걸러진 표, 마크, 그리고 **키 있는 리�
| 62 | ROW | → i | 열이 계산하는 행. `인자`는 그 표의 리스트 상태. 열 전용 |
| 63 | PICK | … → … v | `인자`개 아래의 값을 복사해 올린다(0이면 맨 위). 타입과 대상도 그대로 |
| 64 | SLIDE | … v → v | 맨 위 값 아래의 `인자`개(1 이상)를 버린다 |
-| 65 | FOLD | → n 또는 i | 집계. `인자`의 비트 0–7은 종류(0 count, 1 sum, 2 max, 3 min, 4 first), 8–15는 리스트 상태, 16–31은 뒤따르는 블록의 길이 L. 그 L개 명령이 항목마다 그 리스트의 열처럼 돈다(`ROW`가 항목). count는 블록이 남긴 수가 0이 아닌 항목을 세고, sum·max·min은 블록이 남긴 값과 포함 여부(0이 아니면 포함)로 계산한다. first는 블록이 0이 아닌 수를 남긴 첫 항목의 인덱스(그 리스트의 인덱스)이고 거기서 멈춘다. 포함된 항목이 없으면 count·sum은 0, max·min·first는 `not_found` |
+| 65 | FOLD | → n 또는 i | 집계. `인자`의 비트 0–7은 종류(0 count, 1 sum, 2 max, 3 min, 4 first, 5 distinct: 포함된 항목의 서로 다른 값의 수, −0은 0), 8–15는 리스트 상태, 16–31은 뒤따르는 블록의 길이 L. 그 L개 명령이 항목마다 그 리스트의 열처럼 돈다(`ROW`가 항목). count는 블록이 남긴 수가 0이 아닌 항목을 세고, sum·max·min은 블록이 남긴 값과 포함 여부(0이 아니면 포함)로 계산한다. first는 블록이 0이 아닌 수를 남긴 첫 항목의 인덱스(그 리스트의 인덱스)이고 거기서 멈춘다. 포함된 항목이 없으면 count·sum은 0, max·min·first는 `not_found` |
| 66 | TEXT_COMPARE | t t → n | 바이트 순서로 비교해 0 또는 1. `인자`는 관계(0 LT, 1 LE, 2 GT, 3 GE, 4 EQ, 5 NE, 수 비교 명령의 순서). 앞이 같으면 짧은 쪽이 앞이다 |
| 67 | LIST_FIND | k → i | 키 있는 리스트 `인자`에서 키가 k인 항목의 인덱스. 반씩 나눠 찾는다. 없으면 `not_found` |
| 68 | LIST_HAS | k → n | 그 키의 항목이 있으면 1, 없으면 0 |
@@ -184,6 +184,13 @@ text, 끝이 맞지 않는 바이트는 메시지를 `limit`으로 실패시킨�
인자는 잎 단위 실행에서 모두에 같은 값이고, 한 번의 통과로 답하는 열의 집계(PureShape)에서는 행이 주는 키 쪽에만 올 수 있다
(통과는 인자에 따라 달라지지 않는다).
+**키 범위.** 걸러진 표의 필터, 집계, 걷기의 where(블록 처음의 조건과, 거짓이면 블록 끝으로 가는 JZ)가 키 있는 리스트의 키를 항목을
+읽지 않는 값과 비교하는 조건들(`>=`·`>`와 `<`·`<=`, `==`)을 AND로 가지면, 로드할 때 그 범위를 기록하고 실행할 때 경계 값을 한 번
+계산해 키로 찾은 위치 사이의 항목만 읽는다(O(log n + k)). 범위 밖 항목은 그 조건에서 떨어지므로 필터에서는 언제나 같다(결함 난
+항목도 빠진다). 집계와 걷기에는 나머지 부분이 결함을 낼 수 없을 때만 쓴다(나누기, 넘칠 수 있는 합·곱, 없을 수 있는 키가 없다):
+건너뛴 항목이 돌렸을 일이 없어야 하기 때문이다. 걷기의 경계는 블록이 쓰는 상태·지역 칸·리스트를 읽지 않을 때만 쓴다(경계는
+걷기 전에 한 번 계산하고, where는 항목마다 다시 읽는다). 경계가 결함을 내면 범위 없이 쓰인 대로 돈다.
+
**지역 칸.** 이벤트는 수나 인덱스를 담는 칸 64개를 0으로 시작해 핸들러들과 그 안의 걷기·집계가 함께 쓴다(LOCAL_LOAD·LOCAL_STORE).
상태가 아니라 저장되지 않고, 이름공간을 쓰지 않으며, 보기에는 없다. 한 칸은 한 핸들러에서 한 가지로 쓰여 검증된 타입을 지킨다.
잎 단위 실행에서는 모두에 같은 값이고, 한 번의 통과로 답하는 집계에서는 키 쪽에만 온다.