본문으로 건너뛰기
피드

괄호가 싫어도 한 번은 봐야 할 작은 리스프, 재닛

open-source 약 9분
vote
0
댓글
북마크

글쓴이는 취미 프로젝트용 언어로 작은 리스프 계열 언어인 재닛을 몇 년째 쓰고 있고, 무료 책까지 쓸 정도로 꽂혔다. 핵심은 문법 장난이 아니라 작은 런타임, 네이티브 실행 파일 배포, 파싱 표현 문법, 셸 스크립팅, 매크로, 컴파일 타임 실행이 한데 묶인 실용성이다.

  • 1

    재닛은 핵심 명령이 8개뿐인 작은 명령형 리스프 계열 언어다.

  • 2

    재닛 프로그램은 런타임까지 정적으로 묶은 네이티브 실행 파일로 쉽게 배포할 수 있다.

  • 3

    정규식 대신 파싱 표현 문법을 기본 텍스트 처리 도구처럼 써서 멀티라인 텍스트, 파일 형식, 바이너리까지 다루기 좋다.

  • 4

    컴파일 시점에 값을 만들고 실행 시점으로 넘길 수 있어 자산 임베딩이나 코드 생성 같은 작업이 자연스럽다.

  • 글쓴이는 취미 프로젝트용 언어로 작은 리스프 계열 언어인 재닛에 제대로 꽂혔다고 함

    • 그냥 ‘괄호가 예뻐서’가 아니라, 직접 무료 책까지 썼을 정도로 실사용 경험이 쌓인 상태에서 나온 추천임
    • 글의 목표도 명확함. 리스프를 좋아하는 사람 말고, 아직 안 믿는 개발자에게 “왜 한 번쯤 써볼 만한가”를 설득하는 글임
  • 재닛은 일부러 작게 만든 언어임

    • 명령형 언어고, 일급 함수, 단일 식별자 네임스페이스, 렉시컬 블록 스코프를 갖고 있음
    • 언어 코어는 do, def, var, set, if, while, break, fn 딱 8개 명령으로 구성됨
    • 대신 매크로가 있어서 고수준 제어 흐름이나 편의 문법은 얇은 래퍼로 얹을 수 있음
  • 배우는 진입 장벽은 꽤 낮다고 봄

    • 글쓴이는 런타임 의미론을 “자바스크립트에서 이상한 함정을 빼고 값 타입을 더한 느낌”이라고 설명함
    • 표준 라이브러리 전체가 한 페이지에 들어갈 정도로 작아서, 오후 하나면 언어의 감을 잡을 수 있다는 주장임
    • 이 작고 익숙한 구조가 글쓴이를 처음 끌어들인 이유였다고 함
  • 재닛의 강점 중 하나는 배포가 쉽다는 점임

    • 재닛 프로그램은 재닛 런타임을 정적으로 링크한 네이티브 실행 파일로 컴파일할 수 있음
    • 받는 사람에게 재닛 설치, 의존성 설치, 런타임 설치를 요구하지 않아도 됨
    • 심지어 그 프로그램이 재닛으로 작성됐다는 사실을 말하지 않아도 됨. 이건 작은 명령줄 도구 배포할 때 꽤 큰 장점임
  • 내부 방식도 제법 우아함

    • 재닛은 자기 코드를 바이트코드로 컴파일한 뒤, 그 바이트코드를 재닛 런타임을 시작하는 .c 파일 안에 써 넣음
    • 그 다음 시스템의 C 컴파일러로 이 파일을 컴파일함
    • 재닛 자체가 임베딩하기 쉽게 설계됐기 때문에, 자기 자신을 작은 C 실행 파일 안에 임베드하는 식으로 동작하는 셈임

중요

> 단순한 hello world 네이티브 바이너리가 재닛 1.27.0 기준 애플 실리콘 맥에서 784KB였다고 함. 이 안에 런타임, 가비지 컬렉터, 바이트코드 컴파일러까지 들어감.

  • 텍스트 파싱 쪽은 글쓴이가 거의 과장처럼 칭찬하는 영역임

    • 재닛은 정규식 대신 파싱 표현 문법을 중심으로 텍스트를 다룸
    • 파싱 표현 문법은 멀티라인 텍스트, HTML, JSON 같은 비정규 언어, 심지어 임의의 널 바이트가 들어간 바이너리 포맷도 다룰 수 있음
    • 그냥 패턴 매칭이 아니라 구조적이고 조합 가능한 일급 파서라는 점이 핵심임
  • 셸 스크립팅도 꽤 독특함

    • sh라는 서드파티 라이브러리가 있고, 파이프와 리다이렉트를 재닛 코드 안에서 직접 표현할 수 있음
    • 예시는 ($ find . -name *.janet | say)처럼 생겼음
    • 글쓴이는 이 라이브러리 때문에 재닛이 펄 대안뿐 아니라 꽤 많은 경우에 배시 대안으로도 보인다고 말함
  • 재닛은 임베디드 언어로도 밀고 있음

    • 런타임이 작은 C 라이브러리라서 링크한 뒤 일반 C 함수로 재닛 값을 조작하면 됨
    • 앱에 스크립팅 인터페이스를 붙이거나, 웹사이트에 임베드해서 커스텀 프로그래머블 도메인 특화 언어를 만들 수도 있음
    • 글쓴이는 루아가 임베디드 언어의 사실상 표준이 된 걸 아쉬워하면서, 재닛도 이 영역에서 충분히 매력적이라고 봄
  • 컬렉션은 가변과 불변을 둘 다 기본으로 제공함

    • 불변 컬렉션은 값 의미론을 가짐. 예를 들어 [1 2](take 2 [1 2 3])는 메모리 주소가 달라도 같은 값으로 취급됨
    • 가변 컬렉션은 참조 의미론을 가짐. 같은 키와 값을 가진 해시 테이블이라도 서로 다른 객체면 구분됨
    • 모든 언어가 복합 불변 값을 표준 라이브러리 안에 자연스럽게 넣어두진 않기 때문에, 이 부분도 글쓴이에겐 큰 장점임
  • 진짜 리스프 맛은 매크로에서 나온다고 함

    • 글쓴이는 사실 이게 재닛을 배워야 하는 진짜 이유라고 보지만, 초반에 말하면 독자가 도망갈까 봐 뒤로 미뤘다고 함
    • 매크로를 안 배워도 재닛 코드는 쓸 수 있지만, 배우면 “코드를 쓰는 코드”를 작성하는 특유의 재미가 생김
    • 컴파일 타임에 실행되는 코드와, 그 코드가 만들어낼 런타임 애플리케이션 코드를 동시에 머릿속에 들고 있어야 해서 사고방식이 꽤 달라짐
  • 재닛 매크로는 위생적 매크로가 아니고, 함수 전용 네임스페이스도 없음

    • 그런데 리터럴 함수를 언쿼트할 수 있게 해서 참조 투명한 매크로를 만들 수 있다고 함
    • 글쓴이는 이걸 섬세한 문제에 대한 굉장히 단순하고 우아한 해법으로 봄
    • 여기서 재닛의 더 큰 특징인 “컴파일 타임 값을 런타임으로 넘기는 능력”으로 이야기가 이어짐
  • 재닛은 컴파일할 때 실행한 결과를 스냅샷으로 저장할 수 있음

    • 프로그램을 컴파일하면 최상위 명령들을 실행하고, 실행이 끝난 뒤 프로그램 상태의 스냅샷을 디스크에 기록함
    • 공유 참조도 보존되고, 가변 값은 스냅샷을 재개한 뒤에도 계속 변경 가능함
    • 제너레이터는 다음에 재개할 명령 위치를 기억하고, 클로저도 그대로 살아 있음
  • 이 기능은 매크로 없이도 꽤 강력함

    • 게임 자산을 미리 계산하거나, 파일을 컴파일 타임에 읽어서 최종 바이너리에 임베드할 수 있음
    • 글에서는 SQL 스키마 파일을 읽고 데이터베이스 바인딩을 자동 생성하는 예시도 언급함
    • 대부분의 언어에서는 빌드 스크립트나 별도 코드 생성 도구로 빼야 할 작업을 언어 안에서 자연스럽게 처리하는 느낌임
  • 문법 취향도 글쓴이에겐 큰 매력 포인트임

    • 괄호를 많이 쓰지만 리스트는 [], 테이블은 {}를 써서 단조로움을 줄임
    • 가변 리터럴은 @"mutable string"처럼 항상 @ 접두사를 붙임
    • 익명 함수는 (fn [x] (+ 1 x))로 쓰고, |(+ 1 $)처럼 표현식을 함수로 들어 올리는 축약 문법도 있음
    • 백틱 문자열은 원하는 개수의 백틱으로 감싸서 이스케이프 고민 없이 문자열 내용을 넣을 수 있음
  • 재닛은 전통보다 편안함을 택한 리스프임

    • CAR 대신 first, PROGN 대신 do, LAMBDA 대신 fn, SETQ 대신 def를 씀
    • nil은 빈 리스트가 아니라 별도 타입이고, 불리언도 일급 값임
    • 링크드 리스트 중심 전통도 거의 보이지 않음. 리스프 계열이지만 옛 관습을 숭배하는 언어는 아니라는 얘기임

기술 맥락

  • 재닛의 선택은 “작은 언어를 어디에 쓸 것인가”라는 질문에 꽤 선명하게 답해요. 거대한 애플리케이션 플랫폼이 아니라, 배포 가능한 명령줄 도구와 임베디드 스크립팅, 텍스트 파서 쪽에서 강점을 잡은 거예요.

  • 네이티브 실행 파일 배포가 중요한 이유는 사용자 경험 때문이에요. 작은 도구 하나 쓰자고 런타임과 패키지 매니저를 설치하라고 하면 바로 마찰이 생기거든요. 재닛은 런타임까지 묶어서 1MB 안팎 바이너리로 내보낼 수 있으니 이 부담을 줄여요.

  • 정규식 대신 파싱 표현 문법을 전면에 둔 것도 흥미로운 선택이에요. 로그 몇 줄 찾는 수준을 넘어 설정 파일, 마크업, 바이너리 포맷처럼 구조가 있는 입력을 다루려면 정규식은 금방 지저분해지거든요. 재닛은 이 작업을 언어의 기본 감각에 가깝게 끌어올린 셈이에요.

  • 컴파일 타임 실행과 스냅샷은 빌드 도구와 런타임 코드의 경계를 흐리게 만들어요. 파일을 미리 읽고, 바인딩을 생성하고, 계산 결과를 바이너리에 넣는 식의 작업을 별도 파이프라인 없이 언어 안에서 처리할 수 있기 때문이에요.

이 글의 재미는 재닛을 ‘리스프니까 멋짐’으로 밀지 않는다는 데 있음. 작은 명령줄 도구, 파서, 임베디드 스크립팅처럼 개발자가 실제로 귀찮아하는 영역을 꽤 정면으로 찌른다.

댓글

댓글

댓글을 불러오는 중...

open-source

NIPA, 260명 규모 오픈소스 컨트리뷰션 아카데미 시작

정보통신산업진흥원이 2026 오픈소스 컨트리뷰션 아카데미 발대식을 열고 13주간의 프로젝트 활동을 시작했음. 국내 개발자들이 GitHub 기반 글로벌 협업 환경에서 코드, 문서, 버그 수정, 풀 리퀘스트를 직접 경험하게 하는 프로그램임.

open-source

그누보드7, 디딤과 손잡고 멀티클라우드 도입 문턱 낮춘다

에스아이알소프트가 클라우드 전문기업 디딤과 협력해 그누보드7 기반 웹서비스 구축·운영 환경을 넓히기로 했다. 커뮤니티, 쇼핑몰, 예약, 구독형 서비스 같은 실무 프로젝트에서 서버 구성과 운영 부담을 줄이는 게 핵심이다.

open-source

오픈소스 컨트리뷰션 아카데미 출범, 국내 개발자 260여 명 참여

정보통신산업진흥원이 2026 오픈소스 컨트리뷰션 아카데미 발대식을 열고 13주간의 활동을 시작했다. 11개 프로젝트팀의 멘토와 멘티 260여 명이 글로벌 오픈소스 프로젝트 기여를 목표로 코드 개발, 문서화, 오류 수정 등을 진행한다.

open-source

NIPA, 국내 개발자 260명 규모 오픈소스 컨트리뷰션 아카데미 시작

정보통신산업진흥원이 2026 오픈소스 컨트리뷰션 아카데미 발대식을 열고 국내 개발자의 글로벌 오픈소스 프로젝트 참여를 지원한다. 11개 프로젝트팀, 멘토·멘티 260여 명이 13주 동안 깃허브 기반 협업, 코드 리뷰, 문서화, 오류 수정 등을 실제로 경험한다.

open-source

Ghostty 엔진을 Emacs 안으로 끌고 온 터미널, Ghostel.el

Ghostel.el은 Ghostty의 libghostty-vt를 기반으로 Emacs 안에서 동작하는 터미널 에뮬레이터다. eat 스타일의 여러 입력 모드, 안정적인 복사 모드, line mode, 자동 password prompt 처리, compile-mode 유사 실행 버퍼, Kitty graphics 지원, 높은 throughput을 앞세워 eat/vterm과 차별화함.