Files
coollang/samples
coolguyandClaude Opus 5 5593b54772 std: 표준 라이브러리 — effect 다형성이 처음으로 검사된다
std/list.cool, string.cool, int.cool, bool.cool. 본문 없는 선언이고
런타임이 구현한다. 이 파일들은 구현이 아니라 시험대다.

부채 상환이 아니라 검증이다. std가 없을 때 List.each는 모르는 이름이라
조용히 통과했다. "모르는 것을 틀렸다고 말하지 않는다"는 맞는 원칙이지만,
그 그늘에 검사되지 않는 영역이 숨어 있었다.

넣자마자 샘플 01이 깨졌다 — List.each에 Result를 반환하는 클로저를 넘기고
그 안에서 ?를 쓰고 있었다. each는 값을 남기지 않는 클로저만 받고, ?는
클로저 밖으로 나가지 못하며, 결과를 버릴 방법은 언어에 없다. map으로
고쳤다. 이것이 std를 먼저 한 이유 그 자체다.

- IR은 이제 모듈 그래프 전체를 받고 전역 이름은 "<경로>#<이름>"으로
  정규화된다. 별칭은 가져오는 쪽의 선택이므로 실행 의미에 남아서는 안 된다.
- 본문 없는 선언은 런타임 구현으로 낮아지고, 그 이름은 모듈 파일에서 온다
  (std/list.cool의 each = "list.each"). 별칭과 무관하다.
- prelude 없음. std도 명시적으로 가져온다.
- samples/12: effect 변수가 호출 지점에서 실제로 해소된다는 증거.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019ZVDeU6KLuUVL3gs18Hm3E
2026-08-30 15:47:44 +09:00
..

samples — 문법 탐침

여기 있는 .cool 파일은 명세가 아니라 탐침이다. 목적은 docs/thesis.md의 v0 성공 기준 중 "체감" 항목 — 확정된 규칙으로 짠 코드가 사람이 읽을 만한지 — 을 눈으로 확인하는 것. 문법 정의는 docs/grammar.ebnf.

파서는 아직 없으므로 이 파일들은 컴파일되지 않는다.

파일 검증 대상
01_capability_signature capability 파라미터, effects 절 어순, capability struct 관용구
02_higher_order_effects effect 변수, 구문 수준 제한, 명시적 인스턴스화
03_scope_concurrency TaskScope, 이름 있는 scope, 중첩 시 수명 표현
04_enum_match_interface enum 정의 본문이 interface surface에 들어가는 경로
05_move_errors move/affinity 검사기가 거부해야 하는 코드 (자원을 직접 정의)
06_affine_closure callable affinity (fn vs affine fn), own과의 직교성
07_module_interface interface artifact가 담아야 할 것 전부
08_syntax_errors 파서가 거부해야 하는 코드
09_type_errors 타입 검사기가 거부해야 하는 코드 (외부 타입 0개)
10_effect_errors effect 검사기가 거부해야 하는 코드 (capability를 직접 정의)
11_exhaustiveness exhaustiveness 검사기가 거부해야 하는 코드

05, 08, 09, 10은 통과하면 안 되는 파일이다. 각 함수 주석의 [E-...] 태그가 기대 진단이며, 넷의 목적이 다르다 — 08은 파서가, 09는 타입 검사기가, 10은 effect 검사기가, 05는 move/affinity 검사가 거부해야 한다. 단계별로 파일을 나눈 이유는 앞 단계가 첫 오류에서 멈추면 뒤 단계 케이스에 영영 도달하지 못하기 때문이다.

05, 09, 10에는 외부 타입이 하나도 없다. 전부 모듈 안에서 정의되므로 검사기가 빠져나갈 구석이 없다 — 검사기에 이빨이 있는지 보는 파일들이다. 10은 capability를 직접 정의해야 메서드의 effect가 알려지고, 05는 affinity의 뿌리가 capability라 자원 타입을 정의해야 affine임이 유도된다.

12는 표준 라이브러리가 생긴 뒤에야 가능해진 파일이다. std가 없을 때는 List.each가 모르는 이름이라 조용히 통과했다 — "모르는 것을 틀렸다고 말하지 않는다"는 맞는 원칙이지만 그 그늘에 검사되지 않는 영역이 있었다.

01~04, 06, 07은 coolc check를 통과한다 (exit 0).

modules/는 모듈 경계다. coolc check modules/area.cool이 import를 따라 shapes를 먼저 검사하고, coolc iface modules/shapes.cool이 downstream이 보는 표면과 그 해시를 보여준다.

run/은 실제로 돈다. coolc run run/hello.cool. 이 파일들은 검사를 통과한다가 아니라 무엇을 출력하는지까지 말한다 — 기대 출력이 주석에 있고 같은 것을 test/가 검사한다. main이 선언한 capability만 런타임이 넘기므로, 파라미터에서 Console을 지우면 출력할 방법이 프로그램 안에 없다.

파서는 첫 오류에서 멈춘다(오류 복구 미구현). 타입 검사기는 오류를 전부 모은다.

확정된 표기

  • 어순: fn 이름(파라미터) effects {...} -> 반환타입. 함수 타입도 동일: fn(a) effects e -> b
  • 파라미터는 기본이 빌림(use, 무표기). 소유 이전만 own 유표기. capability든 클로저든 일반 affine 값이든 규칙은 하나다
  • 파라미터 밖(반환 타입, struct 필드, channel 원소)은 항상 owned, 무표기
  • 제네릭은 대괄호: 타입 List[a], 식 map[Int, String, {fs.read}](xs, f). 인덱싱 연산자는 두지 않는다 (List.at)
  • 수식어 순서: own / mut가 먼저, 타입 수식어 affine은 타입 안
  • 모듈: 파일 = 모듈, pub이 exported, import "domain/path" as Name
  • 재수출: reexport Name (전용 키워드 — hash 전파를 동반한다)
  • effect 집합: effects {Type.method, ...}, 빈 집합은 생략
  • effect 변수: [e: effects] 선언, 합집합 e1 | e2는 결과 위치 전용
  • 문 구분은 줄바꿈 (Go식 자동 삽입)
  • 블록은 식. 마지막 식이 값이고 return은 조기 탈출 전용
  • ifmatch는 식. match 가드 없음
  • scope: scope inner = outer { ... } — 부모를 구문에 명시
  • 타입 이름은 그 타입의 함수 이름공간: String.len(s), File.close(f)
  • 리스트 리터럴 [a, b, c], 빈 리터럴은 타입 주석 필요
  • 오류 전파 ?Result 전용