Mini Shell은 앞의 셋이 못 건드린 모양을 친다 — 파이프 하나는 끝이 둘이고 각각 다른 자식에게 간다. 부모에게 아무것도 안 남고 어느 블록에도 묶이지 않는다. 가장 어려운 자원 코드가 렉시컬하지 않다. 파싱을 자원에서 떼어 놓아 개밥이 처음으로 실제로 돈다 (test 5/5 통과). 보안 정리 (ii)의 구멍 셋 — 전부 "부분 move가 없다"는 하나의 규칙이 닿아야 할 자리가 비어 있던 것: - 열거형 생성자가 인자를 소비하지 않았다. Some(f)를 두 번 쓰면 복제됐고, LRU가 쓰는 우회(affine 값을 열거형으로 나르기)가 그래서 무의미했다 - 소유한 열거형을 두 번 분해할 수 있었다. match가 scrutinee를 늘 빌려서 조각만 owned로 나갔다 — 같은 파이프에서 같은 fd를 두 번 꺼낼 수 있었다 - 점 왼쪽을 이름 해소가 검사하지 않았다. Nonsense.whatever(1)이 통과했고 samples 셋(02, 04, 06)이 이 구멍에 기대고 있었다 (D1과 같은 병) 누수 lint를 넣었다. ?와 return 자리에서 소유하고 있고 아직 안 넘긴 affine 값을 말한다. 저장소 전체 네 곳, 오탐 0건 — naive 판만 걸리고 careful 판은 조용하다. 타입 층 정책은 그대로다 (오용 금지, 누수 허용). 결정: resource라는 새 종류는 넣지 않는다. capability가 이미 그것이고 own self가 정리를 말한다. with는 미룬다 — 두 갈래 중 고르기에 데이터가 부족하고, 셸이 with가 닿지 않는 모양을 보여줬다. List.rest 추가 (첫 원소를 뺀 나머지). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019ZVDeU6KLuUVL3gs18Hm3E
coollang
되돌리기 비싼 결정부터 확정하는 프로그래밍 언어. 현재 v0 — 설계 검증판.
$ coolc check samples/run/hello.cool
$ coolc run samples/run/hello.cool
area = 12
area = 9
area = 3
무엇을 위한 언어인가
세 가지 목표가 나머지 모든 결정을 지배한다.
- 오류를 더 빨리 잡는다 — null 없음, Option/Result, 소진적 match, 확정 초기화, 선언되지 않은 effect는 컴파일 오류.
- 검증이 더 빠르다 — fast path / slow path 분리, 전역 추론 없음, 복잡한 trait solver 없음, 임의 매크로 없음, 인터페이스 해시 기반 무효화.
- 피해 범위가 좁다 — 명시적 capability, ambient authority 없음, affine 소유권.
설계의 전문은 docs/thesis.md, 문법은
docs/grammar.ebnf에 있다.
지금 되는 것
lex → parse → 이름 해소 → 타입 검사 → effect/capability 검사 → move/affinity 검사 → 소진성 검사 → interface 해시 → typed IR → 인터프리터
여섯 종류의 오류를 한국어 진단으로 보고한다: 문법, 이름, 타입, effect, capability, 소유권. 여기에 match 소진성과 두 가지 lint(미사용 import, effect 과잉 선언)가 더해진다.
$ coolc check samples/12_stdlib_effects.cool
samples/12_stdlib_effects.cool:20:14: 선언되지 않은 effect Console.print
(leaks_effect의 effects 절은 {}입니다)
증분 검사
이 프로젝트의 중심 주장이다. 10만 줄 / 200 모듈에서 측정 (bench/bench.ml):
| 시간 | 재검사한 모듈 | |
|---|---|---|
| 전체 검사 (cold) | 253ms | 200 |
| 함수 본문만 수정 | 0.8ms | 1 |
| 함수 시그니처 수정 | 2.5ms | 2 |
핵심은 시간이 아니라 범위다. 본문 수정이 downstream을 한 칸도 건드리지 않는 것, 그리고 시그니처 수정이 사슬 끝까지 가지 않고 해시가 변한 곳에서 멈추는 것 — 이 둘이 아키텍처의 주장 전부다.
시그니처 수정 시나리오에서는 두 모듈 건너의 match가 실제로 깨진다:
m100.cool:15:3: match가 모든 경우를 덮지 않습니다 (빠진 경우: Tri(_))
m101.cool:21:3: match가 모든 경우를 덮지 않습니다 (빠진 경우: Up.Tri(_))
실제로 써본 결과
samples/app은 검사기를 시험하려고 쓴 것이 아니라 일을 하려고 쓴
프로그램이다 — 설정 파서 + 리포트 도구, 2모듈 232줄.
$ coolc run samples/app/main.cool samples/app/example.conf
설정
name = "coollang" (text)
threads = 4 (number)
...
항목 5개, 문제 2개
문제
10행: 이름이 비어 있습니다
11행: = 가 하나여야 합니다: broken = a = b
쓰면서 걸린 것들을 docs/friction.md에 남겼다.
요약하면: 되돌리기 비싼 결정은 하나도 후회되지 않았고, 불편은 전부
되돌리기 싼 것들이었다.
빌드
OCaml 5.x와 dune이 필요하다.
opam install dune
dune build
dune test # 175개 검사
dune exec bench/bench.exe
coolc는 _build/default/bin/main.exe다. 설치하려면 dune install.
저장소 구성
lib/ 컴파일러 (약 4,900줄 OCaml)
lexer.ml 어휘 분석 — 문법을 하나도 모른다
parser.ml 재귀 하강, LL(1), backtracking 없음
resolve.ml 이름 해소 — 모듈 하나만 보고 결정할 수 있는 것
typecheck.ml 타입 + effect + capability
move.ml move / affinity
exhaust.ml 소진성 (Maranget usefulness)
iface.ml interface artifact + 해시
session.ml 모듈 로딩 + 고정점 invalidation
ir.ml 얇은 typed IR
interp.ml 트리 워킹 인터프리터
std/ 표준 라이브러리 (본문 없는 선언, 런타임이 구현)
samples/ 예제 — 통과용 9개, 일부러 틀린 것 7개
bench/ 증분 루프 측정
v0의 성격
이것은 쓸 수 있는 언어가 아니라 설계가 옳은지 증명된 언어다. 되돌리기 비싼 결정 — 문법, 타입, effect, capability, 소유권, 증분 아키텍처 — 이 전부 코드와 테스트로 못 박혔고, 빠른 검증 루프라는 시스템 속성이 측정으로 증명됐다.
그래서 이 코드를 통째로 버리고 v1로 번역해도 잃을 것이 없다. 애초에 그것이 v0의 목적이었다.
아직 없는 것: 진짜 컴파일(해석 실행만 한다), 병렬 실행(scope는 순차),
파일·네트워크 IO, 완전한 제네릭, 에디터 지원, 패키지 관리자. 표준
라이브러리는 len, each, map, concat, show 수준이다.
이름
언어는 coollang, 툴체인 바이너리는 coolc. 소스 확장자는 .cool.