고전 사중주

교과서 프로그램 네 개를 한꺼번에 언어에 던졌다. 각각이 의심스러운 soft spot을 겨눈다: 행렬곱은 중첩 컨테이너로, Game of Life는 세대 갱신으로, 스도쿠는 쓰고 되돌리는 백트래킹으로, 자릿수 vector의 계승은 고정폭 정수로. 넷 다 양 native backend에서 첫 시도에 정답, 새 버그 제로. probe 주도 수정 26 릴리스 뒤, 아무것도 넘어지지 않는 하루는 헛스윙한 probe가 아니다 —— 그것은 방법 전체가 향하던 측정이며, 다른 것과 똑같이 기록된다.

mereexamplesmethodtestinglanguage-design

이 연재의 지금까지의 probe는 모두 「부서져 있을 법한 것」을 겨눴고, 대부분 맞았다. Part 마지막인 이 이야기는 내기를 뒤집는다: 고전 프로그램 네 개를, 각각이 최근 작업으로 의심스러워진 서브시스템에 기댄다는 이유로 골라, 한꺼번에 돌려서 무엇이 넘어지는지 본다. 행렬곱은 중첩 컨테이너(Vec[Vec[float]])와 그 아래의 copy-on-store 의미론에 기댄다. Game of Life는 「현세대를 읽으며 다음 세대를 쓴다」에. 스도쿠는 「쓰고 되돌린다」에 —— 숫자를 쓰고, 재귀하고, undo가 정말로 undo함을 믿어야 하는 백트래킹 솔버다. 그리고 큰 수의 계승은, 정수 이야기가 명시적으로 주지 않는 것 —— 임의 정밀도 —— 에, 일부러 기댄다.

넷, 버그 제로

넷 다, interpreter와 C backend에서, 첫 실행에 정답이었다. 행렬곱은 엄밀하다. glider는 4세대마다 대각선으로 한 칸 이동하고, 8세대 뒤에는 Conway가 말하는 그대로의 자리에, 다섯 칸으로 잔해 없이 앉는다. 9×9 퍼즐은 알려진 유일해로 풀린다. 그리고 계승의 단은 고정폭 이야기를 두 막으로 정직하게 말한다: native의 21!은 양 backend에서 같은 음수로 wrap하고 —— 같은 wrap이 동일하게, 라는 것은 두 Part 전의 폭 통일에 대한 작은 승리이기도 하다 —— 그다음 자릿수 vector에서 30!의 33자리가, 마지막 0까지 올바르게 나온다. 버그가 가장 있을 법한 네 곳에서, 새 버그 제로. 26 릴리스의 발견과 수정 뒤에, 이것은 지루한 결과가 아니다. 방법이 줄곧 가리키던 측정이다: 언어의 테스트된 표면이, 교과서 한 장 분량을 넘어 자랐다. 사중주는 examples 디렉터리에 더해진다 —— 그중 하나는 새 이름 으로. Game of Life는 구문 설탕 쇼케이스로 이미 존재했고, probe로 역사를 덮어쓰는 것은 그 자체가 작은 버그였을 테니까.

유일한 아픔과, Part의 장부

하나만 아팠는데, 그것은 의미론이 아니라 메시지였다. 행렬 코드는 셀을 작은 다형 helper 너머로 읽는다. 타입 검사기가 s + get a i * get b j를 보는 순간, helper의 요소 타입은 아직 미해결 변수다 —— 그래서 수치 연산자는 int로 default하고, 이윽고 나오는 “expected float, got int“는 진짜 원인에서 먼 무고한 식을 가리킨다. defaulting 규칙 자체는 남는다(두 Part 전에 저울질하고 문서화했다). 바뀐 것은 에러가 자신을 설명하게 된 것이다 —— hint가 defaulting을 지명하고, 두 도피로를 제시한다: 파라미터에 주석하거나, 한쪽 피연산자에 ascription을 붙이거나. 그리하여 Part의 장부: channel은 닫는 법을 배웠고, supervisor는 포기하는 법을 배웠고, select는 불필요함이 판명됐고, capture 해석의 버그가 pub/sub broker 안에서 죽었고, 고전 넷이 깨끗하게 돌았다. 「끝」의 툴킷은 세 개의 작은 프로그램이 요구했기에 존재한다. 사중주는 토대의 나머지가 버티고 있다고 말한다. 다음 Part가 무엇을 잴지는, 언제나처럼, 아직 정해지지 않았다 —— probe가 고른다.

← Back to Mere: 언어를 만들다