# 왜 Janet인가? (2023)

> Clean Markdown view of GeekNews topic #30126. Use the original source for factual precision when an external source URL is present.

## Metadata

- GeekNews HTML: [https://news.hada.io/topic?id=30126](https://news.hada.io/topic?id=30126)
- GeekNews Markdown: [https://news.hada.io/topic/30126.md](https://news.hada.io/topic/30126.md)
- Type: GN+
- Author: [neo](https://news.hada.io/@neo)
- Published: 2026-06-03T09:05:40+09:00
- Updated: 2026-06-03T09:05:40+09:00
- Original source: [ianthehenry.com](https://ianthehenry.com/posts/why-janet/)
- Points: 1
- Comments: 2

## Topic Body

- **Janet**은 작은 Lisp 방언이지만 명령형 언어·일급 함수·단일 식별자 네임스페이스·어휘적 블록 스코프를 갖춰 단순하게 시작할 수 있음
- **핵심 언어**는 `do`, `def`, `var`, `set`, `if`, `while`, `break`, `fn` 8개 명령만으로 구성되고, 매크로가 더 강력하거나 편리한 제어 흐름 래퍼를 만들어 줌
- **배포성**은 Janet 프로그램을 Janet 런타임과 정적으로 링크한 네이티브 실행 파일로 컴파일해, 사용자에게 Janet이나 의존성 설치를 요구하지 않는 방식으로 확보함
- **파싱 표현 문법(PEG)** 은 정규식보다 단순하고 강력하며 예측 가능하고, **sh**는 파이프와 리다이렉트를 Janet 안에서 표현하게 해 CLI 작성 범위를 넓힘
- **컴파일 시점 실행**은 톱레벨 명령을 먼저 실행한 뒤 프로그램 상태 스냅샷을 디스크에 저장해, 매크로 없이도 런타임으로 값·공유 참조·제너레이터·클로저 상태를 넘길 수 있게 함

---

### 단순한 핵심
- Janet은 명령형 언어이며 일급 함수, 단일 식별자 네임스페이스, 어휘적 블록 스코프를 가짐
- 언어 핵심은 `do`, `def`, `var`, `set`, `if`, `while`, `break`, `fn` 8개 명령으로 작게 유지됨
- 매크로는 더 강력하거나 편리한 고수준 제어 흐름 래퍼를 가능하게 함
- 런타임 의미론은 익숙하고, [표준 라이브러리](https://janet-lang.org/api/index.html) 전체가 한 페이지에 들어갈 만큼 언어의 나머지 부분도 작음

### 네이티브 배포와 임베딩
- Janet 프로그램은 Janet 런타임을 정적으로 링크한 네이티브 실행 파일로 쉽게 컴파일할 수 있음
- 배포받는 사용자는 Janet, 프로젝트 의존성, 그 밖의 별도 구성요소를 설치할 필요가 없음
- Janet은 자신을 바이트코드로 컴파일한 뒤, Janet 런타임을 시작하는 `.c` 파일 안에 그 바이트코드를 기록하고, 시스템 C 컴파일러로 해당 C 파일을 컴파일함
- 간단한 “hello world” 네이티브 바이너리는 1MB보다 작고, Janet 1.27.0의 aarch64 macOS 기준 크기는 784K였음
- 이 바이너리에는 전체 Janet 런타임, 가비지 컬렉터, 바이트코드 컴파일러까지 들어가므로 런타임에 Janet 코드를 평가하는 프로그램도 만들 수 있음
- Janet 런타임은 작은 C 라이브러리라 링크한 뒤 일반 C 함수를 호출해 Janet 값을 조작할 수 있음
- 웹사이트에도 임베드할 수 있고, [Toodle](https://toodle.studio/)처럼 사용자 정의 프로그래머블 DSL을 가진 정적 사이트를 만들 수 있음

### 텍스트 파싱과 서브프로세스 DSL
- Janet의 텍스트 처리는 정규식 대신 파싱 표현 문법을 기반으로 함
- 파싱 표현 문법은 정규식보다 단순하고 강력하며 예측 가능하고, 줄 단위에 묶이지 않아 여러 줄 텍스트를 파싱할 수 있음
- HTML, JSON, 그 밖의 비정규 언어를 파싱할 수 있고, 임의의 null 바이트가 있는 바이너리 파일 형식도 다룰 수 있음
- [sh](https://github.com/andrewchambers/janet-sh)는 파이프와 리다이렉트를 Janet 코드 안에서 직접 표현하게 하는 서드파티 셸 스크립팅 DSL임

```janet
($ find . -name *.janet | say)
```

- 이 DSL은 Janet을 Perl의 합리적 대안에서 꽤 넓은 범위의 프로그램에 대해 Bash의 합리적 대안으로 끌어올림

### 컬렉션과 문법 감각
- Janet 컬렉션 타입은 가변과 불변 형태를 모두 가짐
- 불변 컬렉션은 값 의미론을 가지므로, 불변 벡터 `[1 2]`는 메모리 주소가 달라도 `(take 2 [1 2 3])`와 구분되지 않음
- 가변 컬렉션은 참조 의미론을 가지므로, 해시 테이블 `@{:x 1 :y 2}`는 자기 자신과만 같고 같은 키와 값을 가진 다른 해시 테이블은 별도 객체임
- 문법은 괄호를 널리 쓰지만 리스트에는 `[]`, 테이블에는 `{}`를 사용해 형태를 나눔
- 가변 리터럴은 `@"mutable string"`처럼 항상 `@` 접두사를 붙임
- 익명 함수는 `(fn [x] (+ 1 x))`로 쓰고, `|(+ 1 $)`처럼 `|`로 표현식을 함수로 들어 올리는 축약 표기도 제공함
- 스플랫 또는 스프레드는 `;`를 사용해 `(+ ;args)`처럼 표현함
- 백틱 문자열은 원하는 개수의 백틱으로 열고 같은 개수의 백틱으로 닫을 수 있으며, 백틱 문자열 안에서는 `\n` 같은 이스케이프 시퀀스가 적용되지 않음
- 나머지 매개변수는 `.` 대신 `&`를 써서 `(defn foo [first & rest] ...)`처럼 작성함
- Janet은 reader macro를 지원하지 않아 문법 자체가 고정되고, Janet을 읽을 줄 알면 모든 Janet 프로그램을 읽을 수 있음

### 매크로와 컴파일 시점 상태
- Janet 매크로는 코드를 작성하는 코드이며, 컴파일 시점에 값과 추상 구문 트리를 조작하는 현재 실행 흐름과 미래에 실행될 애플리케이션 코드 흐름을 동시에 다루게 함
- Janet 매크로는 위생적(hygienic)이지 않고, 함수용 별도 네임스페이스도 없음
- 하지만 리터럴 함수를 unquote할 수 있어 완전히 참조 투명한 매크로를 작성할 수 있음
- Janet 프로그램을 컴파일하면 톱레벨 명령, 일반 문장, 함수 선언 등을 먼저 실행한 뒤 프로그램 상태의 스냅샷을 디스크에 기록함
- 이 스냅샷은 공유 참조를 보존하므로, 다시 시작한 뒤에도 가변 값을 계속 변경할 수 있음
- 제너레이터는 다음 재개 시 실행할 명령을 기억하고, 클로저도 닫힌 값을 유지함
- 매크로는 컴파일 시점 코드 실행의 특수한 형태지만, 매크로 없이도 이 능력을 사용할 수 있음
- 게임에서는 스플라인을 미리 처리할 수 있고, 컴파일 시점에 파일을 읽어 최종 바이너리에 자산을 넣을 수 있으며, 임의의 부수 효과도 수행할 수 있음
- [Janet for Mortals](https://janet.guide/macros-and-metaprogramming/)는 SQL 스키마 파일을 기반으로 데이터베이스 바인딩을 자동 생성하는 예를 보여주며, 이런 작업은 대부분의 언어에서 꽤 어렵다고 평가함

### Lisp 전통보다 편안함
- Janet은 오래된 Lisp 관습을 그대로 따르지 않음
- `CAR`는 `first`, `PROGN`은 `do`, `LAMBDA`는 `fn`, `SETQ`는 `def`로 이름 붙음
- `nil`은 빈 리스트가 아니라 독립 타입이고, 불리언은 일급 값임
- `EQ`, `EQL`, `EQUAL`, `EQUALP` 계열을 피하고, 연결 리스트도 거의 보이지 않음

## Comments



### Comment 58852

- Author: neo
- Created: 2026-06-03T09:38:14+09:00
- Points: 1

###### [Hacker News 의견들](https://news.ycombinator.com/item?id=48367907) 
- Janet에는 아쉬운 점이 있음. 주로 **패키지 관리 버전 지정**이 부족하고, 고급 HTTP 라우팅 같은 라이브러리 전반이 부족함  
  그래도 JPM으로 바이너리와 스크립트를 만들 수 있고 이식성이 좋다는 점은 정말 마음에 듦. 예전에 개념 증명으로 Playdate 게임 콘솔에 Janet 프로그래밍 언어를 올려본 적도 있음  
  Janet으로 코드 쓰는 건 즐기지만, 그럴 때마다 사람들이 내가 이 언어를 만든 줄 아는 점은 좀 곤란함
  - Julia Evans가 Julia로 Gunzip을 시각화한 재미있는 글이 있음: [https://jvns.ca/blog/2013/10/24/day-16-gzip-plus-poetry-equa...](<https://jvns.ca/blog/2013/10/24/day-16-gzip-plus-poetry-equals-awesome/>)  
    “Janet이 Janet을 쓴다” 버전도 해보면 좋겠음
  - **jeep**는 써봤는지 궁금함: [https://github.com/pyrmont/jeep/](<https://github.com/pyrmont/jeep/>)  
    의존성을 벤더링하고 jpm 없이도 현대적인 Janet 번들을 쉽게 설치할 수 있게 해줌
  - 서버 쪽이 필요하면 veqq가 말한 것처럼 자체 경량 HTTP 서버를 구현한 **joy**가 있음. 클라이언트가 필요하면 Janet C API로 libcurl이나 다른 HTTP 클라이언트를 감싸는 건 꽤 간단함  
    LLM 개발에 열려 있다면 래퍼는 LLM에게 쓰게 하고 실제 로직은 Janet으로 작성할 수 있음
  - **고급 HTTP 라우팅**이 구체적으로 무엇을 뜻하는지 궁금함. 웹 관련 작업은 전부 [https://github.com/joy-framework/joy](<https://github.com/joy-framework/joy>)로 하고 있어서, 빠진 기능이 있다면 아마 일주일 안에 넣을 수 있을 것 같음

- 같은 개발자가 더 일찍 만든 비슷한 언어로 **Fennel**도 있음. Lua로 컴파일되고 구현도 전부 Lua로 되어 있음  
  자체 표준 라이브러리가 없어서 Janet의 파서 라이브러리 같은 좋은 것들이 많이 빠져 있지만, Lua를 내장한 환경에서 스크립트를 작성하기에는 좋음  
  [https://fennel-lang.org/](<https://fennel-lang.org/>)
  - Fennel은 정말 좋고 Clojure 계열에 입문하기에도 좋은 방법임. 가장 큰 불만은 디버깅이 전형적인 **트랜스파일 지뢰밭**이라는 점임  
    Fennel과 Lua VM 사이의 연결이 매우 취약하고, Janet 디버거와 REPL의 품질에 절반도 못 미침. Fennel은 훨씬 이식성이 좋고 LuaJIT 덕분에 SBCL을 압도할 수도 있어서 아쉬움이 큼  
    다만 트랜스파일 경험이 완전히 발목을 잡는다고 봄. 우회책은 있지만 `debug.setinfo`를 구현해도 `match` 블록 같은 덜 즐거운 경계 사례를 만나게 됨  
    LuaJIT2를 포크해서 디버깅과 오류 구조를 언어 투명성에 더 맞게 고치는 데 큰 가치가 있다고 봄. 그러면 Fennel 같은 언어가 훨씬 매력적으로 보일 것임

- 글쓴이는 예전에 HN에서도 다뤄진 이 도구들을 **Janet**으로 만들었음  
  [https://bauble.studio](<https://bauble.studio>)  
  [https://toodle.studio](<https://toodle.studio>)  
  이 두 흥미로운 예술 도구 덕분에 한동안 Janet에 꽤 기대하게 됨

- Janet이 관심을 받는 걸 보면 늘 반가움. 현대적인 기능 중 하나로 **sandbox**를 꼽고 싶음  
  “인터프리터가 특정 시스템 리소스를 쓰지 못하도록 기능 집합을 비활성화한다. 한 번 비활성화한 기능은 다시 활성화할 방법이 없다.”  
  [https://janet-lang.org/api/misc.html#sandbox](<https://janet-lang.org/api/misc.html#sandbox>)
  - 정말 멋진 기능이지만, 평균적인 프로그래머가 이런 **샌드박싱**을 필요로 하는 상황이 무엇인지 궁금함

- “SETQ is def”를 보고 처음엔 소리 내서 “뭐?”라고 했음. SETQ는 바인딩을 만들지 않고 업데이트만 하기 때문임  
  문서([https://janet-lang.org/docs/bindings.html](<https://janet-lang.org/docs/bindings.html>))를 읽어보니 글쓴이가 실제로 틀렸고, “def로 만든 바인딩은 불변”이라고 되어 있음. 아마 “SETQ is set”을 말하려던 것 같음  
  Janet은 Guile, Tcl, CL 사이의 적절한 지점처럼 보여서 정말 좋아하고 싶은데, 람다와 제어 흐름 연산자에 **대괄호 벡터**를 쓰는 데 본능적인 거부감이 있음. Clojure도 마찬가지로 도저히 넘기 어렵지만, 충분히 노력하면 가능할지도 모르겠음  
  그리고 현재 LSP/SLIME 상태가 어떤지도 궁금함. 요즘엔 꽤 중요함
  - Clojure 문법에서 **대괄호** 사용은 매우 일관적이고 꽤 논리적임  
    둥근 괄호를 쓰면 목록의 첫 요소가 나머지 목록을 어떻게 해석할지 정함. 예를 들어 `(func a b c)`는 함수 실행, `(macro x y z)`는 매크로 확장, `([p q r] …)`는 매개변수 벡터로 시작하고 실행식이 뒤따르는 “맨몸” 함수 본문임  
    대괄호는 요소들이 같은 “종류”이고 첫 요소가 특별하지 않을 때 씀. 예를 들어 `(defn f [a b c] …)`는 같은 종류의 매개변수 모음이고 첫 매개변수가 특별하지 않으며, `(let [a 1 b 2] …)`도 바인딩 모음이고 첫 바인딩이 특별하지 않음  
    떠오르는 유일한 예외는 `case`에서 여러 매칭 요소를 묶는 경우인데, 이는 편의성을 위한 것임. 이 논리를 이해하고 나니 생각이 바뀌었고, 이후로는 아름답다고 느끼게 됨
  - 대괄호와 중괄호를 그냥 안 써도 됨. `[1 2 3]` 대신 `(array 1 2 3)`을 쓰면 되고, `(fn [x] (+ 1 x))` 대신 `(f (x) (+ 1 x))`를 쓰면 됨  
    필수는 아님
  - Clojure에서 **구조 분해**가 어떻게 동작하는지 이해하면 대괄호가 맡는 역할이 분명해짐

- 일정 길이를 넘는 시스템 스크립트에서는 Janet이 내게 **sh, Python, awk** 등을 대체함  
  스크립트 실행 시작 시간이 매우 빠르고, 내 시스템에서는 hyperfine 기준 1.4ms로 dash의 1ms와 비슷함. 컴파일된 실행 파일이 아니라 스크립트 기준임  
  `sh-dsl` 모듈 덕분에 `($ cmda w x | cmdb y z)`처럼 셸 명령을 아주 우아하게 적을 수 있음. 디버깅을 위해 이미지를 로드할 수 있는 기능도 큰 도움이 됨  
  아주 최근에 쓰기 시작했지만 이미 가장 좋아하는 언어 중 하나가 될 것 같고, 이전에 써본 다른 Lisp는 SICP용 MIT Scheme뿐임
  - 내게는 **babashka**가 sh, Python, awk 등을 대체해줬음

- 이 글은 신선함. 인터넷의 **AI 이전 토론** 냄새가 남  
  새로운 언어, 새로운 문법, 수년간 코드를 써온 사람들의 치열한 논쟁이 있음. 누군가 AI가 허용되지 않는 온라인 커뮤니티를 시작하면 좋겠음
  - 최근 흐름을 따라오지 않았다면, digg.com의 최신 재출시는 **봇 공세**를 감당하지 못해 실패했음  
    사실 바로 전 재출시라고 해야 할 듯하고, 지금은 새 홈페이지가 또 있는 것 같음. 온라인 커뮤니티에서 AI를 안정적으로 막는 방법을 처음 찾는 사람은 아마 매우 부자가 될 가능성이 큼  
    [https://www.techspot.com/news/111698-digg-relaunch-fails-two...](<https://www.techspot.com/news/111698-digg-relaunch-fails-two-months-ai-agents-spambots.html>)
  - AI가 허용되지 않는 온라인 커뮤니티를 어떻게 만들 수 있을지 자주 생각함. 특히 온라인 **익명성**을 무너뜨리지 않고 해내는 방법이 어려움  
    일종의 “인간성 증명”은 풀기 힘든 문제임
  - AI의 놀라운 점은 AI 열성 지지자가 아니어도, AI와 무관한 대화에 AI를 끼워 넣을 수 있다는 것임. 반대자들이 대신 해줌
  - 그런 곳은 아마 **lobsters**일 듯함. 300개가 넘는 댓글이 달린, 아마 사이트 역사상 최대 규모의 토론 뒤에 AI 글이 금지됨  
    운영진이 정한 정확한 규칙은 “의미 있는 인간 저작”이었지만 속으면 안 됨. lobsters에는 LLM에 이념적으로 반대하는 사람이 많음. 기술이 얼마나 “의미 있게” 적용됐는지는 별로 중요하지 않음  
    내 작업은 AI가 닿았다는 이유만으로 쓰레기로 분류됐고, AI를 사용한다고 말했을 때 나를 노출증 환자나 페티시스트라고 부르는 사람들도 있었음. 가입을 생각하는 사람에게 미리 알려두고 싶음
  - 아이러니하게도 최상위 댓글인 이 댓글이 이제 **AI**에 관한 내용이 됨

- “리터럴 함수를 언쿼트할 수 있게 해서 Janet은 완전히 참조 투명한 매크로를 작성할 수 있게 한다” 같은 문장에 Lisp 사람들은 정말 추상적인 것들에 흥분하는 듯함  
  길거리의 평범한 사람에게 이렇게 말하면 아마 도망가려 할 것임
  - **참조 투명성**이 없는 리터럴 포함 C 매크로 예시는 이렇음  
    `#define MULTIPLY(x, y) x * y`  
    `int result = MULTIPLY(2 + 3, 4); // 14`  
    어떤 말의 뜻을 모른다고 해서 그게 나쁜 건 아님. 표현을 보면 아마 그런 뜻으로 말한 것 같음  
    프로그래밍에서 반복적으로 나타나는 패턴과 문제에 대한 공유 언어를 갖는 건 좋은 일임. “저 프로그래머 집단은 참 이상하다”는 식으로 용어를 조롱하는 건 무의미하고 역효과만 남
  - 길거리의 평범한 사람에게 **객체 지향 프로그래밍 언어**와 그 장점을 설명해본 적이 있는지 궁금함
  - 약 1년 전부터 Scheme 인터프리터를 작성하기 시작해서 꽤 멀리 갔음. 몇 달 전 새 직장을 얻으면서 중단함  
    다시 시작할까 생각 중인데, 틈새 기능이 구현할 가치가 있는지 고민됨. 내겐 구현도 어려움. `dynamic-unwind`를 건너뛰고, 어쩌면 `call/cc`도 빼버린 뒤 디버깅 가능성, 생태계, 성능, 패키지 관리에 집중하는 편이 나을지도 모르겠음
  - “무슨 일 하세요?”라는 질문을 받을 때마다 대체로 그런 반응을 받음  
    그래서 “컴퓨터 관련 일을 합니다” 정도로 아주 모호하게 말하거나, “별로 재미있는 일은 아니에요”라고 하고 화제를 바꾸려 함. 조금만 더 구체적으로 말하면 사람들이 출구를 찾기 시작함
  - 평균적인 프로그래머도 그럴 듯함  
    솔직히 Lisp 계열 커뮤니티는 작았기 때문에 오히려 이득을 본 면이 있다고 생각함. 예를 들어 아주 오래된 Design Patterns조차 상속보다 합성을 선호하라고 경고했는데도, 객체 지향 프로그래머들은 여전히 15단계 깊이의 계층 구조를 만들었음

- Janet을 처음 접했을 때 이 문서들이 정말 도움이 됐음  
  [https://janetdocs.org/tutorials](<https://janetdocs.org/tutorials>)  
  [https://janet.guide/](<https://janet.guide/>) 글쓴이가 만든 것임

- HN에 가끔 올라오는 Janet 글에 끌렸지만, 다들 높게 평가하는 **Janet for Mortals**는 전혀 필멸자를 위한 책처럼 느껴지지 않았음
  - 더 부드러운 입문 자료도 있음: [https://janetdocs.org/tutorials](<https://janetdocs.org/tutorials>)
  - 의외임. 이 언어는 매우 직관적이고 단순하며 기억해야 할 규칙도 아주 적음. Lisp이긴 하지만 표면적이 매우 작음  
    다른 언어와 비교하면 Janet은 정말 배우기 쉬운 편이라, 그 책이 어렵다는 게 놀라움. 책은 읽지 않았지만 언어에는 어느 정도 익숙하고, 솔직히 칭찬밖에 할 게 없음
  - 개인적으로는 **매크로 문법**이 너무 앞부분에 나와서 막히지만, 그 뒤에는 가치 있는 내용이 정말 많음
  - Haskell에서 그런 느낌을 받았음. Haskell은 내게 너무 어렵지만, 문법 자체는 마음에 듦  
    Janet은 Lisp 2.0처럼 보이니 문법도 Lisp식임

### Comment 58847

- Author: neo
- Created: 2026-06-03T09:05:41+09:00
- Points: 1

###### [Lobste.rs 의견들](https://lobste.rs/s/y0euno/why_janet_2023) 
- Janet을 시작한 지 **10개월** 만에 APL 계열 언어 말고는 거의 다 잊어버릴 정도로 빠졌고, 커뮤니티 [문서 사이트](https://janetdocs.org/)를 운영하면서 [튜토리얼](https://janetdocs.org/tutorials/learn-to-program)도 쓰는 중임  
  시작 3주 안에 개인 스크립트들을 전부 다시 썼고, 새로 만드는 운영 소프트웨어도 Janet으로 작성함  
  Janet은 구현상 언어 전체가 거의 **해시맵**처럼 동작해서 `(keys (curenv))`로 로컬 심볼을, `(keys (getproto (curenv)))`로 코어 심볼을 볼 수 있고, 원하면 해시맵 기반으로 CLOS 비슷한 것도 만들 수 있으며 [구현체](https://git.sr.ht/~subsetpark/fugue)도 있음  
  [Joy 웹 프레임워크](https://github.com/joy-framework/joy)로 20개쯤 되는 웹사이트와 여러 서비스를 512MB 무료 VPS 하나에서 돌리고 있고, 관련 [튜토리얼](https://janetdocs.org/tutorials/Joy-Web-Framework)도 작성함  
  다만 “불변 컬렉션”이라는 표현은 실제와 다소 다르며, 표준 라이브러리는 대체로 가변 값을 돌려주므로 지금은 불변성을 고집할 이유가 크지 않음  
  컴파일 시점 값을 실행 시점으로 넘기는 기능이 특히 강력했음. 예를 들어 성경 `.tsv`를 컴파일 때 해시맵으로 바이너리에 넣어두면 실행 시에는 조회만 하게 되고, `embed`를 쓴 Go 버전보다 [두 배 빠른](https://codeberg.org/veqq/verse-reader#performance) 결과도 나왔음  
  Go로 같은 걸 직접 해시맵 형태로 구현하면 훨씬 길어지지만, Janet으로는 [Lisp to Go 컴파일러](https://codeberg.org/veqq/Joe/src/branch/master/joe.janet)도 46줄로 만들 수 있었음  
  Ian Henry가 말한 더 흥미로운 부분은 Janet이 **클로저 상태를 이미지/세션 간에 보존**한다는 점으로, `(curenv)` 해시맵에 관련 환경을 저장했다가 새 REPL 세션에서 복원해도 클로저 내부 상태가 이어짐
  - Janet으로 만든 멋진 예로는 https://bauble.studio 가 있고, 제작 과정 글도 https://ianthehenry.com/posts/bauble/building-bauble/ 에 있음. WASM 활용이 눈에 띔  
    Lisp 기반 음악 DSL인 https://lisp.trane.studio/ 도 있고, 논문 https://dl.acm.org/doi/abs/10.1145/3677996.3678285 과 결과 예시 https://x.com/greg_ash/status/1824218993118388708 도 볼 만함  
    직접 만든 라이브러리도 있는데, 여러 자료구조 위에서 SQL 비슷한 [질의 문법](https://codeberg.org/veqq/declarative-dsls)을 제공함  
    데이터프레임 삽입·갱신·CSV 저장/로드를 지원하고, Datalog와 miniKanren도 포함하며, APL처럼 벡터화된 연산도 가능함  
    Janet에서 J를 직접 쓰는 [jnj](https://git.sr.ht/~subsetpark/jnj)도 있고, Joy Web Framework에는 `(var account (db/find-by :account :where {:login (auth-result :login)}))` 같은 [DB 질의 DSL](https://github.com/joy-framework/joy/blob/master/docs/database-queries.md)이 있으며 실제 웹사이트 [인증 코드](https://codeberg.org/veqq/janetdocs/src/commit/848dcbd8e54ad5e0e8555abc0b5c72dab1720282/routes/home.janet#L79)에도 쓰임
  - 원문에서 “불변 컬렉션”이라고 쓴 건 표현이 부정확했던 것 같음. 의도한 건 컬렉션이라기보다 **복합 값 타입과 참조 타입**에 가까움  
    “불변 컬렉션”이라고 하면 영속 자료구조가 떠오르는데, 그런 건 유용하더라도 Janet 기본 기능은 아님  
    실제로 마음에 드는 건 값 타입과 참조 타입의 대칭성이고, 글 끝에 “immutable composite values”라고 쓰긴 했지만 내가 쓴 게 아니었다면 나도 뜻을 바로 알아채기 어려웠을 듯함

- Janet은 신선하고 **임베드 가능한 언어**라서 게임 엔진 같은 프로젝트의 내장 스크립팅에 써보고 싶음  
  DLL 교체 없이 빠른 반복을 위한 핫 리로드가 필요한 곳에 잘 맞아 보이고, Lua도 훌륭하지만 Janet이 어떤 면에서는 더 표현력이 좋아 보임

- Janet은 언어로서 정말 멋지고, 언젠가 Zig 프로젝트의 **스크립트 언어**로 써보고 싶음. 더 많은 사람이 Janet을 언급하는 게 반가움
  - Janet 커뮤니티에서 Janet의 **Zig 구현체**에 대한 논의가 실제로 있음: https://janet.zulipchat.com/#narrow/channel/399615-general/topic/Updates.20on.20a.20Zig.20port.20of.20Janet/with/590865945

- 좋아 보이긴 하지만 이미 [babashka](https://babashka.org/)로 Clojure 스크립팅에 익숙해지고 있어서 비슷하게 느껴짐. **임베드 가능성** 말고 놓치고 있는 큰 장점이 있는지 궁금함  
  “나머지 인자를 둔 배열 구조 분해가 잠재적으로 비싼 복사를 일으킨다” 같은 부분은 전반적으로 덜 함수형처럼 보여서 마음에 들지 않음
  - Janet의 킬러 기능 중 하나는 내장 [PEG](https://janet-lang.org/docs/peg.html) 지원이라고 봄. 게임 개발 사이드 프로젝트용 [텍스트박스 DSL을 만들 때](https://alectroemel.com/posts/2023-06-02-textbox-part1.html) 정말 편리했음  
    다른 언어로 텍스트를 파싱할 때마다 아쉬워지는 기능임
  - 그런 식의 구조 분해는 자주 쓰는 방식이 아니고, Janet 배열/튜플은 연결 리스트가 아님  
    Janet은 작고 임베드 가능한 Clojure라기보다는, **함수형 프로그래밍 지원이 더 나은 Lua**에 가까움
