Files
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

58 lines
1001 B
Plaintext

// 실행 의미를 한 파일에 모은 것: ?, mut, struct, match, scope.
//
// 기대 출력:
// 7
// 6
// err
// in scope
import "cool.dev/std/int" as Int
pub capability Console {
fn print(s: String) effects {Console.print}
}
pub enum E {
Bad,
}
pub copyable struct P {
x: Int,
y: Int,
}
pub fn half(n: Int) -> Result[Int, E] {
if n % 2 == 0 {
Ok(n / 2)
} else {
Err(Bad)
}
}
pub fn twice(n: Int) -> Result[Int, E] {
let a = half(n)?
let b = half(a)?
Ok(a + b)
}
pub fn show_res(r: Result[Int, E]) -> String {
match r {
Ok(v) => Int.show(v),
Err(_) => "err",
}
}
pub fn main(c: Console, root: TaskScope) effects {Console.print} {
let mut total = 0
let p = P { x: 3, y: 4 }
total = total + p.x + p.y
c.print(Int.show(total))
c.print(show_res(twice(8)))
c.print(show_res(twice(7)))
scope sc = root {
sc.spawn(fn() {
c.print("in scope")
})
}
}