가변 데이터를 도입하면 공유가 생기고, 공유가 생기면 pair 세 개를 세는 답이 3·4·7·무한대로 갈립니다. SICP 연습문제 3.16 을 Go 로 재현하고, 같은 함정이 Go 슬라이스 append 에서 어떻게 나타나는지 실측했습니다. 후반부는 디지털 회로 시뮬레이터입니다. 원서와 같은 시각(8·11·16)을 재현했고 전가산기 진리표를 전수 검증했습니다.
Posts for: #Programming
Go 로 읽는 SICP Part 7: 시간이 들어오면 치환 모델이 무너진다
SICP 3장은 대입을 도입하고 그 대가를 절 하나를 써서 계산합니다. 치환 모델이 폐기되고 환경 모델이 들어옵니다. Go 클로저가 실제로 힙에 프레임을 만드는 것을 탈출 분석으로 확인했고, Go 1.22 의 루프 변수 변경이 정확히 이 프레임 이야기라는 것을 두 시맨틱을 나란히 실행해 보였습니다. 몬테카를로 예제에서는 난수 생성기 결함으로 π 가 2.72 로 나온 사고를 그대로 실었습니다.
Go 로 읽는 SICP Part 6: 1985년에 쓰인 Go 인터페이스 설계 지침
SICP 2.4~2.5 의 데이터 지향 프로그래밍은 Go 인터페이스 설계 이야기와 거의 같은 내용입니다. 명시적 디스패치·디스패치 테이블·메시지 패싱 세 가지를 Go 로 모두 구현하고, Go 인터페이스가 그중 어느 것인지 판정했습니다. 표현 문제(expression problem)는 컴파일 에러로 직접 확인했고, 제네릭 산술 타워에서 i×i 가 정수 -1 까지 내려오는 것도 재현했습니다.
Go 로 읽는 SICP Part 5: 파이프라인으로서의 프로그램, 그리고 quote 가 없는 언어
map, filter, accumulate 만으로 프로그램을 신호 처리 파이프라인처럼 조립하는 SICP 2.2.3 을 Go 로 옮기고, Go 1.23 의 iter.Seq 판과 나란히 놓았습니다. 여덟 퀸은 92개 해를 재현했습니다. 후반부는 기호 데이터입니다. Go 에 quote 가 없다는 사실이 여기서 처음으로 아프게 다가옵니다.
Go 로 읽는 SICP Part 4: 데이터란 무엇인가 — 저장 공간 없는 pair
SICP 2장은 데이터가 무엇인지 다시 묻습니다. 답은 “약속을 지키는 것이면 무엇이든 데이터"이고, 증거로 저장 공간이 전혀 없는 pair 를 클로저만으로 만들어 보입니다. Go 로 그대로 옮겨 봤고, 제네릭으로 옮기려다 Go 타입 시스템의 천장에 정확히 부딪혔습니다. 컴파일 에러를 그대로 실었습니다.
Go 로 읽는 SICP Part 3: 함수를 돌려주는 함수, 그리고 제네릭이 필요해지는 순간
SICP 1.3 은 프로시저를 인자로 넘기고 반환값으로 돌려주는 방법을 다룹니다. Go 로 옮기면 원서에 없던 것이 하나 생깁니다. 타입 시그니처입니다. 추상화의 계약이 눈에 보이고, 대신 코드가 길어집니다. 뉴턴법을 고정점 탐색으로 분해하고, 연습문제 1.45 의 평균 감쇠 횟수를 n=2부터 32까지 전부 측정했습니다.
Go 로 읽는 SICP Part 2: 프로시저는 재귀인데 프로세스는 반복이다
SICP 1장의 핵심은 코드의 모양과 실행의 모양이 다르다는 것입니다. 재귀적으로 생긴 프로시저가 반복적인 프로세스를 만들 수 있고, 그 구분이 성능을 가릅니다. 그런데 Go 에서는 이 구분이 통째로 지워집니다. 실측으로 확인하고, 왜 그런지와 무엇으로 대신할지를 정리했습니다. 페르마 소수 판정과 카마이클 수는 전수 검증했습니다.
Go 로 읽는 SICP Part 1: 마법사 책은 왜 아직도 살아 있나
1984년에 나온 프로그래밍 교재 하나가 40년이 지나도 계속 언급됩니다. SICP 는 어떤 책이고, 누가 썼고, MIT 는 왜 이 책으로 가르치던 과목을 스스로 폐지했는지 정리했습니다. 그리고 이 시리즈가 Scheme 대신 Go 를 쓰는 이유와, Go 로는 잘 안 되는 지점 세 곳을 실측 데이터와 함께 미리 밝혀 둡니다.
번역글: 컴포넌트와 마이크로커널
Pragmatic Programmers의 Dave Thomas가 쓴 뉴스레터 ‘Components and Microkernels’의 한국어 번역. 1980년대의 소프트웨어 IC 개념과 마이크로커널을 결합해, 배포와 업그레이드가 유연하고 에이전트가 곧바로 쓸 수 있는 애플리케이션 구조를 제안합니다.
달무티 CPU 플레이어 만들기 Part 5: 코드 없이 보는 easy 봇과 hard 봇의 차이
Part 1 부터 Part 4 까지는 코드와 수식이 많았습니다. 이번 편은 개발을 모르는 분도 읽을 수 있게, 달무티 CPU 두 종류가 각각 무엇을 보고 수를 고르는지, 어떻게 겨루게 했고 결과가 어땠는지, 그리고 왜 격차가 이토록 작았는지를 정리했습니다.
Hugo 로 바둑판 도해 그리기 Part 2: 이미지 65장을 표기로 옮기기
이미 발행된 포스트 4편의 바둑판 이미지 65장을 goban 표기로 옮겼습니다. 이미지를 기계로 판독한 방법, 분류기가 세 번 틀린 지점, 그리고 렌더링은 멀쩡한데 내용만 틀릴 뻔했던 버그를 정리합니다.
Hugo 로 바둑판 도해 그리기 Part 1: 왜 shortcode 였나
바둑 입문 포스트를 쓰다 도해를 그릴 방법이 마땅치 않았습니다. 이미지도 mermaid 도 답이 아니었던 이유와, ASCII 표기를 SVG 로 바꾸는 Hugo shortcode 를 만든 과정을 정리합니다.
렉시오 CPU 플레이어 만들기 Part 7: 코드 없이 보는 easy 봇과 hard 봇의 차이
Part 1 부터 Part 6 까지는 코드와 수식이 많았습니다. 이번 편은 개발이나 수학을 모르는 분도 읽을 수 있게, 렉시오 CPU 두 종류가 각각 무엇을 보고 수를 고르는지, 둘을 어떻게 겨루게 했고 결과가 어땠는지, 그리고 무엇은 아직 말할 수 없는지를 정리했습니다.
렉시오 CPU 플레이어 만들기 Part 6: 봇이 약한지 어떻게 아는가
Part 5 는 브라우저에서 한 판 돌려 찾은 결함을 고쳤습니다. 그 방법으로는 “조금 약하다"를 찾을 수 없어 시뮬레이터를 만들었더니, 도구가 전략을 재기도 전에 구현 버그부터 잡아냈습니다. 그리고 봇이 약한 이유를 세 번 틀리고 네 번째에 찾았습니다. 평가 함수는 처음부터 옳았고, 확률이 틀렸습니다.
렉시오 CPU 플레이어 만들기 Part 5: 봇이 아무것도 하지 않는 이유
Part 1~4 에서 설계한 렉시오 hard 봇을 실제로 구현했더니 봇이 거의 모든 턴을 패스했습니다. 개별 항은 전부 맞았고 항을 합치는 방식이 틀렸습니다. 평가 함수가 무너지는 네 가지 자리와, 그 회귀 테스트가 엉뚱한 이유로 통과한 이야기를 다룹니다.
달무티 CPU 플레이어 만들기 Part 4: 만들어 보니 hard 봇이 더 약했다
Part 1부터 3까지의 설계안을 실제로 구현해 시뮬레이션으로 재봤더니, hard 봇이 easy 봇보다 평균 0.6601등 나빴습니다. 무엇을 어떻게 쟀는지, 세 개의 구조 결함이 무엇이었는지, 어떤 고급 기능이 살아남았는지, 그리고 정정 후의 정식 검증 수치를 정리합니다.
8비트의 벽을 넘은 게임들 Part 5: 제약이 사라진 시대에 남은 것
압축·생성·전복이라는 세 가지 돌파구가 40년 뒤에 어떻게 됐는지 정리합니다. 엘리트의 씨앗이 노 맨즈 스카이의 64비트로 이어진 계보, 제약이 사라지자 드러난 역설, 제약을 일부러 되살리는 데모신, 그리고 오늘의 개발에 그대로 쓸 수 있는 여섯 가지 원칙을 다룹니다.
8비트의 벽을 넘은 게임들 Part 4: 메탈기어, 못 그리는 것을 안 그려도 되게 만들다
1987년 MSX2 메탈기어가 하드웨어의 거부를 게임 문법으로 바꾼 과정을 주석 disassembly 로 확인합니다. SCREEN 5 비트맵과 가로 스크롤 부재, 48바이트짜리 방 165개, 스프라이트를 짝지어 색을 늘리고 순서를 섞어 깜빡이는 기법, 원뿔이 아닌 복도형 시야 판정, 그리고 방에 붙어 있는 경보 상태 머신을 다룹니다.
8비트의 벽을 넘은 게임들 Part 3: 엘리트, 우주를 6바이트에 담다
1984년 엘리트가 21,952바이트에 항성계 2,048개를 담은 방법을 주석 disassembly 를 근거로 확인합니다. 트리보나치 씨앗 트위스팅, 두 글자 토큰 이름 생성, 곱셈 명령 없이 도는 3D 회전(민스키 알고리듬), 그리고 타이머 인터럽트로 만든 화면 분할을 Go 재현 코드와 함께 다룹니다.
8비트의 벽을 넘은 게임들 Part 2: 슈퍼 마리오브라더스, 레벨을 그리지 않고 서술하다
슈퍼 마리오브라더스의 disassembly 를 직접 읽고 40KB 안에 32개 스테이지가 들어간 방법을 확인합니다. 레벨 오브젝트 2바이트 인코딩, 월드 1-1 의 실제 바이트 해독, 구름과 수풀이 같은 타일이라는 사실의 바이트 단위 증명, 8프레임 컬럼 파이프라인, 그리고 4.4 및 8.8 고정소수점 물리를 다룹니다.