Lobsters

Lobsters Interview with Sjamaan

CHICKEN Scheme 관리자가 말하는 Scheme 구현과 CHICKEN 6

CHICKEN Scheme 관리자 Peter Bex가 CHICKEN 6의 UTF-8 처리와 출시 지연을 부른 힙 손상 버그, Scheme 생태계의 표준화 문제를 설명합니다. 컴파일러 최적화 구상과 PostgreSQL을 선호하는 이유, REPL 개발 경험도 함께 다룹니다.

AI 요약

CHICKEN Scheme 관리자이자 Clojure 개발자인 Peter Bex가 Scheme 구현, CHICKEN 6, 데이터베이스, REPL, 개발 경험을 이야기합니다. 대학에서 Scheme과 SICP를 접한 뒤 개인 프로젝트에 Lisp를 활용했고, CHICKEN의 실용성과 속도, 커뮤니티에 끌려 패키지인 egg를 만들며 기여를 시작했습니다. 이후 가비지 컬렉션(GC), 매크로 확장기, Irregex 구현 등 런타임과 컴파일러 내부를 익혔습니다.

CHICKEN 6와 Scheme 표준화

Bex는 Scheme의 작은 언어 핵심이 실험적인 구현을 가능하게 하지만, 실제 제품 수준의 구현은 기능을 늘리려는 요구를 받는다고 설명합니다. 표준화는 구현 간 호환성을 높이는 한편, 언어의 최소성을 약화할 수 있습니다. R7RS를 small과 large로 나눈 결정은 적절했다고 봅니다. 다만 일부 주요 Scheme 구현이 R7RS를 사실상 따르지 않고, R7RS large의 빠른 변화와 커뮤니티 합의 부족도 아쉽다고 말합니다.

CHICKEN 6은 R7RS를 기반으로 삼으면서 기존 코드와 CHICKEN 고유 모듈 문법도 유지합니다. 보통 egg를 6으로 옮길 때는 식별자가 모듈 사이에서 이동한 부분을 조금 고치면 됩니다. 이번 버전은 UTF-8 처리를 일관되게 바꾸고 문자열과 바이트 벡터를 분리했습니다. 포트와 입출력도 함께 손봤으며, FFI에서 문자열을 불필요하게 복사하지 않도록 개선했습니다.

출시를 늦춘 원인은 힙 손상 버그였습니다. 처음에는 CHICKEN 위키가 사용하는 Subversion 클라이언트 라이브러리의 콜백 처리에 문제가 있다고 의심했습니다. 그러나 위키 코드를 줄여도 오류가 계속됐고, 심볼릭 링크 뒤에 있는 페이지를 정규 URL로 바꾸는 URI 정규화 코드를 끄자 충돌이 사라졌습니다. 원인은 더 좁혀져 read-symbolic-link에서 발견됐습니다. UTF-8 전환 과정에서 코어 코드가 잘못 바뀐 탓이었습니다.

컴파일러와 런타임의 다음 과제

Bex가 제안한 컴파일러 개선안은 안전한 기본 동작을 유지하면서 불필요한 검사를 줄이는 방식입니다. 예를 들어 car에 쌍이 아닌 값을 넣으면 예외가 발생하지만, 컴파일러가 앞선 pair? 검사나 사용 맥락을 보고 값이 쌍임을 추론하면 검사 없는 연산으로 바꿀 수 있습니다. 현재처럼 최적화가 임시방편에 머물지 않도록, 안전하지 않은 연산과 호출 지점에 삽입하는 사전 조건(prelude)을 분리하는 구상을 소개합니다. 필요한 검사만 제거하고 사용자 코드에도 같은 구조를 적용하는 것이 목표입니다.

날짜와 시간 기능도 정리하고 싶다고 말합니다. POSIX 함수를 쓰는 코어 기능은 복잡하고 쓰기 불편하며, SRFI-19는 여러 달력과 지역화를 지원하는 대신 규모가 큽니다. 공통 타입과 프로토콜의 타임스탬프 파싱을 제공하는 작은 코어 기능이 대안이 될 수 있다고 봅니다. 또 기존 문헌에서 충분히 다루지 않은 약한 참조와 효율적인 GC, FFI, 모듈 간 최적화, 별도 컴파일과 크로스 컴파일 같은 주제에 관심을 보입니다.

데이터베이스와 개발 방식

Bex는 Rails 프로젝트에서 대량 갱신의 성능 문제를 겪으며 SQL의 가치를 배웠습니다. MySQL에서는 문자 집합 문제와 대량 데이터 입력 실패를 겪었고, PostgreSQL로 옮긴 뒤 UTF-8 검증, 트랜잭션 안에서 실행하는 DDL, 원자적인 마이그레이션을 장점으로 꼽았습니다. LISTEN/NOTIFY, 배열, 윈도 함수, CTE도 활용합니다. 반면 SQLite는 기본 설정의 타입 처리와 스키마 변경 제약을 불편하게 느껴 자주 쓰지 않는다고 말합니다.

REPL은 실험과 디버깅에 꼭 필요하지만, 편집기 코드와 실행 중인 상태가 어긋날 때 불편하다고 설명합니다. Clojure에서는 시작 시간이 느려 업무 시간 내내 CIDER REPL을 쓰지만, 버퍼에서 테스트를 지워도 REPL에 남아 있는 상태를 직접 정리해야 합니다. 코드 저장 후 테스트를 실행하는 방식도 선호한다고 덧붙입니다. 테스트가 없는 프로젝트를 최적화할 때는 pg_dump 결과를 기준 파일로 저장하고, 변경 뒤 출력이 달라졌는지 비교해 회귀를 확인한 경험도 소개합니다.

Lobsters 반응

  • @zem — 즐겁게 읽은 인터뷰입니다. CHICKEN을 잠깐 써봤고 지금도 좋은 인상을 갖고 있습니다. 써본 순수 Scheme 중에서는 아마 가장 마음에 들었지만, Lisp 전체로 보면 저는 여전히 Racket을 더 좋아합니다.
  • @pervognsen — 게을러서 직접 찾아보지는 않겠지만, 대화를 이어가는 의미에서 질문합니다. 제가 기억하기로 CHICKEN은 여전히 “Cheney on the MTA” 방식을 쓰나요? C로 컴파일하고 CPS로 연속을 구현하며, C 스택의 alloca로 동적 할당을 처리하고, 스택 오버플로를 스택 복사 GC의 신호로 삼는 방식입니다. 제가 제대로 기억한다면, 오랜 세월 동안 이 방식은 어떻게 작동했나요? 저는 2000년대 중반에 Scheme을 거의 그만 쓰고 따라가지 않게 됐습니다. 컴파일러에 관심 있는 사람으로서 기억에 남은 점은 그 독특한 컴파일 방식입니다.

원문: Alex Alejandre / 번역·요약: Trawling