본문으로 건너뛰기
피드

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

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

슈나이더일렉트릭, 제조 혁신용 오픈소스 프레임워크 ‘라이트하우스 OS’ 구축 참여

슈나이더일렉트릭이 세계경제포럼과 협력해 오픈소스 기반 제조 혁신 프레임워크인 라이트하우스 운영체제 구축에 참여한다. 파일럿 프로젝트는 많은데 전사 확산이 안 되는 제조업의 고질적인 문제를, 검증된 운영 원칙과 5단계 성숙도 모델로 풀겠다는 접근이다.

open-source

OECD 보고서가 본 오픈소스 AI의 경제 효과…성능 90%, 비용은 20%

OECD가 프랑스 G7 의장국 요청으로 작성한 보고서에서 AI 개방성이 경제성장과 기술 주권에 미치는 효과를 분석했다. 오픈웨이트 텍스트 모델은 폐쇄형 모델 대비 약 90% 성능을 내면서 가격은 20% 수준이고, AI 오픈소스 기여가 10% 늘면 GDP가 장기적으로 약 0.5% 증가한다는 추정도 제시됐다.

open-source

마이크로소프트, 오픈소스 AI 데이터 분석 플랫폼 Data Formulator 0.7 공개

마이크로소프트 리서치가 분산된 기업 데이터를 연결하고 분석·시각화하는 오픈소스 플랫폼 Data Formulator 0.7을 공개했어. 데이터 커넥터, 컨텍스트 기반 AI 에이전트, 데이터 스레드, 인터랙티브 캔버스를 통해 분석 워크플로우를 한 화면 안으로 묶는 게 핵심이야.

open-source

허깅페이스, 375만원대 오픈소스 휴머노이드 플랫폼 공개

허깅페이스가 약 2,500달러, 한화 약 375만원으로 직접 제작할 수 있는 오픈소스 2족보행 휴머노이드 플랫폼 르로봇 휴머노이드를 공개했다. 단순 로봇 모델이 아니라 하드웨어, 조립 문서, 런타임, 시뮬레이션, 데이터 수집, 정책 훈련, 실물 제어까지 포함한 풀스택 플랫폼이라는 점이 핵심이다.

open-source

한국 이더리움 생태계가 ‘보이지 않는 기여자’를 무대로 올리려는 이유

한국에도 이더리움 프로토콜, 합의, 거버넌스, MEV 같은 깊은 영역을 연구하는 기여자가 있지만 글로벌 커뮤니티에 잘 보이지 않는다는 문제를 짚은 글이다. 이더리움 컨소시엄은 6월부터 2~3팀 또는 개인을 뽑아 해외 컨퍼런스, 데브콘, 국내외 네트워크 연결을 지원하는 펠로우십 실험을 시작하려 한다.