2025년에 탐험할 12가지 이국적인 프로그래밍 언어를 살펴봅니다: 무엇이 독특한지, 어디에서 강점을 발휘하는지, 그리고 헤매지 않고 간단히 시도해볼 방법을 안내합니다.

“이국적”이란 곧장 “더 낫다”거나 “더 어렵다”는 뜻은 아닙니다. 보통은 문법, 최적화하려는 대상, 혹은 가르치려는 아이디어에서 비범한 시도를 하는 언어를 가리킵니다.
이 글에서 프로그래밍 언어를 이국적으로 분류하는 기준은 다음 중 적어도 하나에 해당하는 경우입니다:
이국적 또는 에소테릭 언어를 배우는 과정은 종종 재미있고 의외로 교육적입니다. 프로그램이 무엇인지, 데이터가 어떻게 흐르는지, 실제로 얼마나 적은 문법으로도 동작하는지를 재고하게 만들기 때문입니다.
이들 언어의 대부분은 일상 업무용 도구는 아닙니다. 어떤 것은 퍼즐이고, 어떤 것은 연구용 수단이며, 어떤 것은 특정한 좁은 작업에 매우 적합한 대신 다른 작업에는 불편합니다. 보상은 생산성보다 통찰입니다.
2025년은 탐색하기 좋은 시기입니다. 여러 니치 언어들이 **활발한 커뮤니티, 더 나은 문서, 친절한 도구(대화형 REPL, 패키지, 온라인 플레이그라운드)**를 갖추었습니다. 또한 대안적 패러다임에 대한 관심—데이터 작업을 위한 배열 프로그래밍, 규칙을 위한 논리 프로그래밍, 특수 하드웨어 없이 실험할 수 있는 양자 ‘토이’ 환경—이 다시 높아졌습니다.
“기괴함”을 순위로 매기기보다 **계열(families)**로 그룹화했습니다(미니멀리스트, 보이지 않는 코드, 2D, 배열, 논리, 스택 기반, 안전성 중심, 양자). 각 섹션에는 빠르게 시도해볼 수 있는 간단한 "무엇을 시도할지(what to try)" 아이디어를 넣었습니다.
“이국적”은 여러 의미를 가질 수 있으므로 이 목록은 단지 이상한 문법의 나열이 아닙니다. 우리는 2025년에 배우기 실용적이면서도 진정으로 다른 사고방식을 요구하는 언어들을 골랐습니다.
우선 독창성을 봤습니다: 2D 코드, 스택 기반 사고, 규칙/질의, 배열을 기본으로 하는 설계, 양자 회로 등 새로운 정신 모델을 강제하는 언어들.
둘째로 학습 가능성을 우선했습니다. 특이하더라도 "Hello World" 예제, 튜토리얼, 작은 프로그램을 빠르게 실행할 수 있는 길이 있어야 합니다.
셋째로 실제로 쓸 수 있는 도구가 있는지 확인했습니다: 공개 문서, 작동하는 인터프리터/컴파일러, 활발한 저장소 같은 것들. 아무리 훌륭해도 현대 기기에서 실행할 수 없다면 추천하기 어렵습니다.
마지막으로 균형을 고려했습니다—클래식한 에소테릭 언어(퍼즐·사고 실험)와 주류 작업에 아이디어를 전이할 수 있는 진지한 니치/연구용 언어를 섞었습니다.
낯선 코드는 무작위 다운로드처럼 다루세요. 인터프리터와 샘플 프로그램은 컨테이너나 샌드박스(혹은 최소한 임시 폴더)에서 실행하는 것이 좋고, 개인 파일, SSH 키, 클라우드 자격증명에 접근 가능한 환경에 알 수 없는 코드를 붙여넣지 마세요.
자주 실험한다면 “안전한 플레이그라운드” 설정을 표준화하면 편합니다. 예를 들어 인터프리터를 API 뒤에서 실행하고 실행 사이 상태를 초기화하는 작은 폐기형 웹 앱을 띄울 수 있습니다. Koder.ai 같은 플랫폼은 원하는 플레이그라운드(프런트엔드 + 백엔드 + DB 등)를 채팅으로 설명해서 빠르게 스캐폴딩하고, 만족하면 소스 코드를 내보낼 수 있어 유용합니다.
Brainfuck이 이국적인 이유는 단순합니다: 거의 우스울 만큼 작은 명령 집합으로 모든 것을 하려 하기 때문입니다. 언어에는 명령이 여덟 개뿐입니다(+ - < > [ ] . ,), 키워드가 없고, 일반적인 의미의 변수도 없으며, 그 요령을 모르면 읽을 수 있는 구조가 없습니다.
이름 붙은 변수 대신 Brainfuck은 메모리 셀의 테이프와 좌우로 움직이는 포인터를 제공합니다. 현재 셀을 증가/감소시키고, 포인터를 이동시키고, 대괄호로 루프를 만듭니다. 전적으로 퍼즐을 푸는 느낌이죠.
Brainfuck은 컴퓨터가 계산하는 데 필요한 최소 요소를 몸으로 배우게 합니다. 다음을 생각하게 만듭니다:
인터프리터나 컴파일러가 실제로 무엇을 하는지 궁금했다면 Brainfuck은 훌륭한 연습 대상입니다.
주로 프로그래밍 퍼즐, 이론 토론, 코드 골프, 인터프리터 작성 연습에서 사용됩니다.
“Hello World”(클래식 버전):
++++++++++[\u003e+++++++\u003e++++++++++\u003e+++\u003e+\u003c\u003c\u003c\u003c-]\u003e++.\u003e+.+++++++..+++.\u003e++.\u003c\u003c+++++++++++++++.\u003e.+++.------.--------.\u003e+.\u003e.
값을 설정하고 문자를 출력하는 작은 루프 예제:
+++++[\u003e++++++++\u003c-]\u003e.
팁: 온라인 Brainfuck 인터프리터의 단계별 실행 기능을 사용해 명령 하나하나 실행하면서 테이프가 어떻게 변하는지 관찰하세요.
Whitespace는 오직 공백(스페이스), 탭, 줄바꿈만 의미가 있는 에소테릭 언어입니다. 그 밖의 모든 문자는 주석으로 처리됩니다. 즉, 에디터에서는 완전히 빈 파일처럼 보이는 소스가 유효한 프로그램일 수 있습니다.
대부분의 언어는 가시적인 키워드와 구두점을 사용합니다. Whitespace는 그 기대를 뒤집습니다: 전체 소스가 에디터에서 “보이지 않는” 상태일 수 있습니다. 관습, 도구, 인간의 시각에 프로그래밍이 얼마나 의존하는지 보여주는 완벽한 예입니다.
Whitespace는 파싱과 토큰화의 최저 수준을 고민하게 만듭니다:
작은 파서나 렉서(lexer)를 만들어봤거나, 실제 코드에서 보이지 않는 문자(혼합된 탭/스페이스, 이상한 줄끝)로 디버깅해본 적이 있다면 Whitespace는 그 고통을 학습용 연습으로 바꿔줍니다.
디버깅이 가장 큰 난관입니다. 하나의 잘못된 탭이나 줄바꿈이 전체 의미를 바꿀 수 있습니다.
시각화 도구(공백/탭/줄바꿈을 가시화해 주는 도구)와 “보이지 않는 문자 보기” 기능을 제공하는 편집기를 사용하세요. 그렇지 않으면 나중에 자기 코드를 다시 읽는 것조차 고역입니다.
문자나 숫자를 출력하는 가장 작은 Whitespace 프로그램을 작성한 뒤, 동일한 동작을 일반 언어(Python/JavaScript)로 구현하고 비교해보세요:
Befunge가 이국적인 이유는 프로그램이 위에서 아래로 읽히는 깔끔한 텍스트 덩어리가 아니기 때문입니다. 대신 2D 격자 위에 존재하며, 명령 포인터가 오른쪽, 왼쪽, 위, 아래로 이동하면서 코드에 배치한 화살표를 따라갑니다. 작은 회로도나 핀볼 테이블을 탐색하는 느낌에 가깝습니다.
대부분 언어에서는 코드가 고정된 텍스트입니다. Befunge에서는 프로그램 자체가 실행 중에 스스로를 편집할 수 있습니다: 명령이 격자에 새로운 문자를 써서 다음에 실행될 내용을 바꿀 수 있습니다. 그런 자기수정 능력이 언어 정체성의 일부이며, 퍼즐 같은 놀라운 프로그램을 만듭니다.
Befunge는 데이터 흐름과 상태 기계적 사고를 유도합니다: 경로를 계획하고, 루프는 문자 그대로 경로이며, 분기도 ‘방향 전환’입니다. 여러 방향 흐름이 자연스러우므로(해석기는 여전히 한 번에 한 명령을 실행하더라도) 병렬처럼 보이는 흐름을 생각하기 쉬워집니다.
퍼즐, 코드 골프, 기이한 생성 행동이 필요한 인터랙티브 설치, 코드 자체가 예술의 일부인 짧은 데모에 적합합니다.
다음은 한 자리 숫자를 읽어 그 숫자를 두 배로 출력하는 간단한 Befunge-93 프로그램입니다:
\u00262*.
어떤 Befunge 인터프리터에서든 실행해보세요: 숫자(0–9)를 입력하면 결과가 출력됩니다. 거기서부터 방향 화살표(> < ^ v)와 추가 셀을 넣어 명령 포인터가 직선 대신 “경로”를 따라가게 해보세요.
Hexagony가 이국적인 이유는 프로그램이 텍스트의 한 줄이 아니라 육각형 벌집 모양의 셀들 위에 배치되기 때문입니다. 명령 포인터는 그 격자를 가로질러 이동하고, 가장자리에서 회전하거나 규칙에 따라 이동합니다. 보드 게임을 탐색하는 것처럼 느껴집니다.
Hexagony는 공간적 사고를 요구합니다: 어디에 명령을 놓느냐가 무엇을 하느냐만큼 중요합니다. 이로 인해 다음을 연습하기 좋습니다:
대부분 탐색용입니다. 업무에서 Python이나 JavaScript를 Hexagony로 대체하진 못하지만, 인터프리터와 명령 포인터, 제어 흐름이 어떻게 작동하는지에 대해 감각을 날카롭게 해줍니다.
작은 격자를 상상해보세요. 각 셀에 한 글자 명령을 넣습니다. 시작 셀에 명령 포인터와 방향(육각형 격자에서는 여섯 방향 중 하나)을 설정한 뒤:
처음 연습은 단지 방향만 바꾸고 하나의 문자를 출력하는 작은 프로그램을 한 단계씩 실행해보는 것입니다—탐색이 곧 제어 흐름이라는 감을 잡기에 충분합니다. 안전한 플레이그라운드를 원하면 온라인 인터프리터와 단계별 실행을 사용하세요(참고: /blog/how-to-try-esoteric-languages-safely).
대부분 언어는 절차적 단계를 서술하게 합니다: 이것을 하고, 저것을 하고, 반복하라. Wolfram Language는 종종 규칙을 기술하게끔 만들어 실행 모델이 이국적으로 느껴집니다—관계와 변환을 기술하고 시스템이 이를 적용하도록 맡기는 방식입니다.
핵심적으로 Wolfram Language는 기호적(symbolic)이고 규칙 기반입니다. 패턴을 작성해 표현식의 일부를 매칭하고 어떻게 다시 쓸지 정의합니다. 흐름을 수동으로 제어하기보다 패턴 매칭과 변환 규칙에 의존해 표현식을 결과로 이끌어갑니다.
이 방식은 **항(term) 재작성(term rewriting)**을 소개합니다: 계산을 반복적 치환으로 보는 사고입니다. 많은 알고리즘이 소수의 재작성 규칙과 이를 적용하는 전략에 불과하다는 직관을 기르게 합니다. 또한 구조화된 표현식을 대상으로 한 패턴 매칭 직관도 길러줍니다.
규칙 기반 프로그래밍은 변환 모델링에 강합니다: 대수식 단순화, 수식 재작성, 트리 조작, 형식 간 변환, 규칙이 절차보다 중요한 시스템 표현 등에서 특히 유용합니다.
다음 코드를 Wolfram Language에 붙여넣고 몇 개 규칙이 어떻게 작동하는지 관찰하세요:
rules = {
x_ + 0 -> x,
0 + x_ -> x,
x_ * 1 -> x,
1 * x_ -> x,
x_ + x_ -> 2 x
};
expr = (a + 0) + (a + a) * 1;
FixedPoint[# //. rules &, expr]
그 다음 한 규칙을 바꿔(예: 분배법칙 관련 재작성 추가) 시스템의 “성격”이 어떻게 달라지는지 확인하세요.
APL과 그것의 현대적 후계자 BQN은 ‘이국적’입니다. 기본 정신 모델을 뒤집기 때문입니다. 단일 값과 루프 대신 모든 것을 배열으로 취급하고 대부분 연산이 전체 컬렉션에 자동으로 적용됩니다.
일반 언어에서는 리스트에 숫자를 더하려면 루프나 헬퍼가 필요합니다. APL/BQN에서는 "10을 더하다"가 당연히 "모든 요소에 10을 더한다"는 의미가 됩니다. 강력한 동작이지만 진짜 충격은 표기법입니다: 밀집된 연산을 나타내는 기호(글리프)가 많아 코드가 간결한 수식처럼 보입니다.
APL/BQN을 쓰면 데이터의 "형(shape)"과 "이걸 전체 데이터 변환으로 표현할 수 있는가"를 먼저 묻게 됩니다. reshape, sort, group, reduce(합), scan(누적 합), outer product 같은 전체 배열 연산으로 절차를 대체하는 사고를 기릅니다.
열, 행렬, 시계열을 다루는 작업에서 배열 언어는 놀랄 만큼 표현적입니다. 그래서 금융과 과학 계산 분야에서 자리잡아 왔고, BQN은 더 현대적인 느낌으로 배열의 힘을 원하는 개발자들을 끌어모으고 있습니다.
익숙한 작업(리스트 정규화, 이동 평균 계산 등)을 고른 뒤 루프 버전과 전체 배열 변환 버전 두 가지로 작성해 보세요. 기호가 낯설더라도 계산을 제어 흐름이 아니라 데이터 흐름으로 보는 법을 배우게 됩니다.
J와 K는 이국적인 이유가 배열(리스트, 표)을 중심으로 사고하고 조합으로 프로그래밍하도록 유도하기 때문입니다. 루프와 임시 변수를 쓰지 않고 작은 함수들의 파이프라인을 구성해 문제를 해결합니다—종종 문장부호처럼 보일 정도로 간결합니다.
두 언어 모두 연산을 체인하는 방식에 중점을 둡니다: 데이터를 가져와 변환하고 축소하고 재구성합니다. J는 입력을 이름 붙이지 않고 동작을 정의하는 "타시틱(tacit)"(포인트-프리) 프로그래밍을 강조합니다. K(및 kdb+의 q)는 간결하고 빠른 데이터 변환을 위해 설계되었습니다.
J/K를 잠깐만 사용해도 다른 언어에서 보이는 관점이 바뀝니다: "변환이 무엇인가?"를 먼저 묻지 "루프가 무엇인가?"를 묻지 않게 됩니다. 파이프라인의 구조 자체가 설명이라는 식으로 프로그램을 읽게 됩니다.
이들 언어는 컬렉션을 받아 요약을 계산하는 작업에 탁월합니다: 정렬, 그룹화, 정규화, 필터링, 탐색적 분석 등에 특히 만족스럽습니다.
J에서 입력을 이름 붙이지 않고 정규화 파이프라인(최솟값-최댓값 스케일)을 정의해보세요:
norm =: (] - <./) % (>./ - <./)
norm 3 10 5 7
또는 문자열에서 단어 수를 세는 작은 텍스트 파이프라인:
#@;: 'J makes pipelines feel like algebra'
기호가 처음엔 빽빽해 보여도 그런 마찰이 의도된 부분입니다: 데이터 연산을 조합 가능한 구성 블록으로 보게 하기 위함입니다.
Forth와 Factor는 이국적인 느낌을 주는 이유가 표현식을 Python이나 JavaScript처럼 쓰지 않기 때문입니다. 대신 주로 스택 연산의 연쇄를 씁니다: 값을 푸시(push), 단어(word, 함수)를 적용, 결과를 다음 단어를 위해 스택에 남깁니다.
스택 언어에서는 순서가 곧 문법입니다. 순서 하나가 의미를 바꾸고, 페이지에는 명시적 명사(변수)가 적게 보입니다. Forth는 핵심이 극히 작기로 유명하며, 매우 작은 코어로도 구현됩니다. Factor는 스택 모델을 유지하면서 풍부한 표준 라이브러리와 도구, 더 구조화된 느낌을 제공합니다.
스택 머신이 어떻게 작동하는지, 왜 인터프리터와 가상 머신에 매력적인지 배우게 됩니다. 또한 작은 단어들을 쌓아 조합하는 조합성(composition) 훈련을 하게 되고, 스택 균형을 유지해야 하므로 엄격한 설계 습관이 길러집니다.
코어가 작아서 임베디드 장치, 게임, 간단한 명령 언어가 필요한 스크립트 등에 내장하기 쉽습니다. Factor는 조합 가능한 프로그램을 빠르게 만드는 놀이터가 될 수 있습니다.
산술과 스택 조작(예: 값 복제, 교체)으로 시작하세요. 그런 다음 작은 계산기 REPL을 만들어 보세요: 토큰을 읽고, 숫자는 푸시, +, * 같은 단어를 실행하고 스택을 출력합니다. 흥미가 생기면 사용자 정의 단어의 사전을 갖춘 미니 인터프리터로 확장해 보세요.
대부분 언어는 "어떻게"를 명시하라고 요구합니다: 여기서 루프를 돌리고, 저기서 분기하고, 변수를 갱신하라. Prolog와 Datalog은 그 반대입니다. 사실과 규칙을 기술하고 질문을 던지면 시스템이 답을 찾아줍니다.
제어 흐름 대신 논리 규칙을 작성합니다. Prolog 프로그램은 종종 세계에 대한 법칙 한 벌과 질의처럼 읽힙니다. 내부적으로 Prolog는 유니피케이션(패턴 매칭)과 백트래킹(가능성을 탐색)으로 해를 찾습니다.
Datalog은 가까운 친척으로 보통 더 제한적입니다(복잡한 용어를 같은 방식으로 허용하지 않음). 대신 확장 가능한 규칙 평가와 데이터베이스 스타일 추론에 강합니다.
선언형 스타일을 사용하면 다른 정신 모델을 갖게 됩니다:
이 아이디어들은 에소테릭 언어를 넘어서 규칙 엔진, 정책 시스템, 쿼리 플래너, 언어 연구에서도 유용합니다.
스케줄링, 설정 규칙, 지식 베이스, 퍼즐 해결—즉 "이 조건들을 만족하는 어떤 해를 찾아라"가 목표인 곳에서 특히 뛰어납니다.
parent(alex, sam).
parent(sam, riley).
grandparent(X, Y) :- parent(X, Z), parent(Z, Y).
이제 질의해보세요:
?- grandparent(alex, Who).
루프를 직접 쓰지 않았습니다; 질문을 던졌습니다. 이 전환이 핵심 교훈이며 그것이 2025년에도 이들 언어가 신선하게 느껴지는 이유입니다.
Rust가 이국적으로 느껴지는 이유는 희귀하거나 생소해서가 아니라 새로운 정신 모델—소유권(ownership)—을 배우게 하기 때문입니다. JavaScript나 Python처럼 가비지 컬렉터를 신뢰하지도, C처럼 수동 해제를 신뢰하지도 않습니다. 대신 값의 "소유자"와 공유 방식에 관한 규칙을 강제합니다.
빌려쓰기 검사기(borrow checker)는 컴파일 타임 심판관입니다. 이중 해제, 사용 후 해제(use-after-free), 데이터 레이스 같은 흔한 버그를 컴파일 단계에서 차단합니다. 처음엔 당신이 의도한 코드가 있어도 Rust는 증거를 요구합니다.
Rust의 큰 교훈은 성능과 안전이 반드시 트레이드오프가 아니라는 점입니다. 수명(lifetimes), 명시적 데이터 흐름, 단독 소유와 공유 접근의 경계를 생각하게 합니다. Rust를 실제로 배포하지 않더라도 이러한 습관은 다른 언어에 전이됩니다.
시스템 도구, CLI 유틸리티, 게임 엔진, 임베디드 프로젝트, 성능이 중요한 서비스 등—속도가 중요하고 충돌이 비용이 큰 곳에 적합합니다.
익숙한 작은 스크립트(단어 세기, CSV 정리, 파일 이름 변경 등)를 Rust로 구현해 보세요. 그런 다음 일부러 버그를 넣어보세요:
Rust는 위험한 동작을 허용하지 않아 컴파일이 되지 않을 가능성이 큽니다. 에러 메시지를 안내서로 삼으세요: 어떤 규칙을 위반했는지 설명하고 보통은 더 안전한 구조를 제안합니다.
양자 프로그래밍이 이국적으로 느껴지는 이유는 전통적인 "함수는 X를 반환한다"가 아니라 양자 회로(큐빗, 게이트, 측정)를 서술하기 때문입니다. 측정 전에 큐빗은 0과 1의 중첩(superposition)을 표현하며, 결과는 확률 분포입니다—같은 프로그램을 여러 번 실행하면 다른 결과가 나올 수 있습니다.
Q#(마이크로소프트)와 Qiskit(IBM)은 회로 연산과 측정 중심으로 구성됩니다. 중첩과 얽힘을 설정하고 측정으로 붕괴시키는 코드를 씁니다. 이런 사고방식은 일반적인 앱 개발과 매우 다릅니다.
실제 양자 하드웨어를 다루지 않더라도 이 도구들은 핵심 개념을 구체화합니다:
대부분의 사람은 시뮬레이터에서 양자 프로그램을 실행합니다. 실제 장치는 노이즈, 대기열, 제약이 있습니다. 시뮬레이터는 여전히 마음 모델을 배우기에 유용합니다.
다음은 두 큐빗을 얽히게(Bell pair) 한 뒤 측정하는 예제입니다:
from qiskit import QuantumCircuit
from qiskit_aer import AerSimulator
qc = QuantumCircuit(2, 2)
qc.h(0)
qc.cx(0, 1)
qc.measure([0, 1], [0, 1])
sim = AerSimulator()
result = sim.run(qc, shots=1000).result()
print(result.get_counts())
대개 00과 11이 주로 보일 것입니다. 이것이 "아하" 순간입니다: 두 큐빗은 독립된 두 비트가 아니라 쌍으로 행동합니다.
목표에 따라 선택하면 쉽습니다. 어떤 언어는 아이디어를 가르치고(논리, 배열, 양자 사고), 어떤 언어는 규율을 가르치며(안전 규칙), 또 어떤 언어는 단순히 문제 해결 능력을 날카롭게 하는 재미있는 제약입니다.
불확실할 땐 약간 불편하지만 해낼 수 있는 걸 고르세요—마찰은 필요하지만 좌절은 원치 않습니다.
1시간 소개:
짧은 튜토리얼을 읽고 3–5개의 작은 예제를 실행하세요. 목표는 코드가 어떻게 보이고 어떻게 실행하는지 파악하는 것뿐입니다.
1일 프로젝트:
완성 가능한 작은 것을 만드세요. 좋은 선택지:
1주 심화:
같은 프로젝트를 더 구조화해서 다시 만드세요: 테스트, 에러 메시지, 문서, 성능 개선. 여기서 언어의 진정한 장단점이 드러납니다.
1일 프로젝트 단계를 가속하려면 Koder.ai를 사용해 간단한 채팅 브리프에서 실행 가능한 웹 러너(React UI + Go 백엔드 + PostgreSQL 등)를 스캐폴드하고, 기획 모드에서 빠르게 반복한 뒤 소스 코드를 내보내는 방법도 있습니다. 언어 호기심을 공유 가능한 실행 가능한 플레이그라운드로 바꾸기 쉬운 방법입니다.
더 많은 실습과 사례를 보려면 /blog를 둘러보세요.
도구(에디터, 러너, 샌드박스, 팀 워크플로우) 관련 맥락이 궁금하면 /pricing을 참고해 무엇이 연습을 지속하게 해줄지 결정하세요.