1단계 최소 IO: File(읽기), Args capability. 권한의 출처는 여전히 런타임 하나이고, IO 오류는 Result[a, String]이다 — 런타임이 사용자 정의 enum을 만들 수 없고, 만들 수 있게 하면 런타임이 프로그램의 타입을 알아야 한다. 2단계 std 확장: fold, filter, push, concat, reverse, is_empty, String.split/trim/starts_with/contains, Int.parse. 3단계 samples/app: 설정 파서 + 리포트 도구, 2모듈 304줄. 검사기를 시험 하려고 쓴 것이 아니라 일을 하려고 쓴 첫 프로그램이다. 산출물은 프로그램이 아니라 docs/friction.md다. 요약: - 되돌리기 비싼 결정은 하나도 후회되지 않았다. capability 전달, effect 명시, 실패를 버릴 수 없음, 소진적 match — 300줄 내내 거추장스럽지 않았고 소진성은 실제로 실수를 잡았다(Value에 경우 하나 추가하니 고칠 자리 넷을 정확히 짚었다). - 불편은 전부 되돌리기 싼 것들이었다. 리스트 n번째 접근이 없어 fold로 우회(40줄), else if가 없어 3~4단 중첩, String.concat이 2항이라 중첩 지옥. 304줄 중 70줄쯤이 이 셋 때문에 존재한다. v0의 질문은 "되돌리기 비싼 결정이 옳은가"였고 답은 그렇다이다. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019ZVDeU6KLuUVL3gs18Hm3E
41 lines
1.2 KiB
Plaintext
41 lines
1.2 KiB
Plaintext
// 표준 라이브러리: 리스트.
|
|
//
|
|
// 본문이 없다. 런타임이 구현하고, 이 파일은 그 계약을 말한다.
|
|
// 그래서 이 파일은 구현이 아니라 시험대다 — effect 다형성이 실제로 쓸 만한지가
|
|
// each, map, fold, filter에서 결정된다. 규칙이 틀렸으면 여기서 드러난다.
|
|
//
|
|
// e는 파라미터의 effect 슬롯에 홀로 나타난다 (결정 위치). 호출 지점에서
|
|
// 인자의 시그니처를 읽어 묶인다 — 추론이 아니라 읽기다.
|
|
|
|
pub fn len[a](xs: List[a]) -> Int
|
|
|
|
pub fn is_empty[a](xs: List[a]) -> Bool
|
|
|
|
// 뒤에 하나 붙인 새 리스트. 제자리 수정이 아니다.
|
|
pub fn push[a](xs: List[a], x: a) -> List[a]
|
|
|
|
pub fn concat[a](xs: List[a], ys: List[a]) -> List[a]
|
|
|
|
pub fn reverse[a](xs: List[a]) -> List[a]
|
|
|
|
pub fn each[a, e: effects](
|
|
xs: List[a],
|
|
f: fn(a) effects e,
|
|
) effects e
|
|
|
|
pub fn map[a, b, e: effects](
|
|
xs: List[a],
|
|
f: fn(a) effects e -> b,
|
|
) effects e -> List[b]
|
|
|
|
pub fn filter[a, e: effects](
|
|
xs: List[a],
|
|
keep: fn(a) effects e -> Bool,
|
|
) effects e -> List[a]
|
|
|
|
pub fn fold[a, acc, e: effects](
|
|
xs: List[a],
|
|
init: acc,
|
|
f: fn(acc, a) effects e -> acc,
|
|
) effects e -> acc
|