난해한 프로그래밍 언어
1. 개요
Esoteric programming language (esolang)
'''일부러''' 다른 프로그래밍 언어에 비해 사용하기 어렵게 만든 언어.
제작 이유는 대부분 컴퓨터 프로그래밍 언어 의 한계를 테스트하기 위해서, 어떤 개념의 증명으로서, 또는 장난하기 위해서(...)이며, '''절대로 실용적인 프로그래밍에 적용하기 위한 의도는 아니다'''. 실제 업무에서 쓰는 프로그래밍 언어는 최대한 다양하게 쓸 수 있으면서도 쉽게 작성할 수 있게 만드려고 애를 쓴다. 다만 실무에 쓰이는 언어 중 난해한 프로그래밍 언어로 꼽히는 언어도 적지 않은데, 쓰기 전용 언어(...)로 악명높은 Perl[1] , 웹 개발자 사이에서 까야 제맛으로 대동단결하는 PHP, Node.js 개발자들에게 애증의 존재인 JavaScript, 태초의 C언어가 그 예.
최초의 난해한 프로그래밍 언어는 제임스 라이언스(James Lyons)와 돈 우즈(Don Woods)가 1972년에 만든 인터칼이라고 한다. 제작 이유는 "자신들이 알고 있는 언어들과 완전히 다른 언어를 만들고 싶어서."
난해한 프로그래밍 언어들은 다양한 방법으로 프로그래머들을 농락하는데, 대략적으로 아래와 같다.
2. 난해한 언어들의 요소들
- 루프문, 대입문, 조건문 같은 정상적인 문법 구조가 거의 없으며, 포인터#s-3, 스택, 큐, 메모리 구조 같은 자료구조에 직접 접근하는 언어가 대부분이다.
- 최소한의 요소만을 가지고 튜링 완전한 언어를 만들어낸다. 즉, 구성요소를 최소화한다. 그 예로, 브레인퍽은 8개의 명령어로, Thue는 명령 1개에 피연산자 2개로 튜링 완전한 언어다.
수학에서는 SKI가 있다. $$Sxyz=xz(yz), Kxy=x, Ix=x$$라는 3개의 함수로 구성된 언어가 튜링 완전한 언어임이 증명되어 있다. 이 중에서 $$I$$(Identity function)는 $$S$$와 $$K$$로부터 연역되므로[2] , 사실상 $$S$$와 $$K$$ 2개로 구성된 가장 심플한 수학적 프로그래밍 언어라 할 수 있다. 여기서 수학과 프로그래밍의 관점의 차이가 존재하는데, 수학에서는 최소주의 및 뇌내 판타지(…)를 충족시켜줄 수 있는 것을 선호하며, 오로지 해당 언어의 구조와 범주에만 신경쓴다. 대부분 실용성의 기준인 특정 프로그램을 만드는게 얼마나 쉬운가, 구현 시 퍼포먼스는 얼마나 빠른가 같은 것들은 전혀 신경쓰지 않는다. 덕분에 SKI는 그것으로 실제 프로그램을 구현하는 것이 삽질일지라도 수학에서는 아주 중요하게 취급되고, 다른 난해한 프로그래밍 언어들도 이런 측면에서는 어느 정도 수학과 관련이 있다.
그러나 이것은 어디까지나 구성이 전에 없이 새로운 언어에만 해당하고,[3] 단순히 기존 언어에다가 명령어 몇 개를 넣고 빼고 하면서 다른 표현 방식으로 치환한 정도에 그치는 것들은 수학적으로도 아무런 의미가 없다. 사실 여기 있는 대부분의 언어도 구성 자체가 새로운 것은 없다고 봐도 된다. 뇌내판타지도 완전히 참신하기는 절대 쉬운 게 아니며, 성공하면 역사에 남는다(…).
단 하나의 함수만 사용하는 언어인 Iota도 있다. $$Ux = xSK$$로 정의된 함수 U로부터 S와 K를 유도해낸다($$S=U(U(U(UU)))$$, $$K=U(U(UU))$$). 다만 U는 함수의 정의에 변수만을 사용한 proper combinator가 아니므로 SKI와 Iota 중 어느 쪽을 더 '작은' 언어로 볼 것인가는 해석의 여지가 있다.
그러나 이것은 어디까지나 구성이 전에 없이 새로운 언어에만 해당하고,[3] 단순히 기존 언어에다가 명령어 몇 개를 넣고 빼고 하면서 다른 표현 방식으로 치환한 정도에 그치는 것들은 수학적으로도 아무런 의미가 없다. 사실 여기 있는 대부분의 언어도 구성 자체가 새로운 것은 없다고 봐도 된다. 뇌내판타지도 완전히 참신하기는 절대 쉬운 게 아니며, 성공하면 역사에 남는다(…).
단 하나의 함수만 사용하는 언어인 Iota도 있다. $$Ux = xSK$$로 정의된 함수 U로부터 S와 K를 유도해낸다($$S=U(U(U(UU)))$$, $$K=U(U(UU))$$). 다만 U는 함수의 정의에 변수만을 사용한 proper combinator가 아니므로 SKI와 Iota 중 어느 쪽을 더 '작은' 언어로 볼 것인가는 해석의 여지가 있다.
- 이상하거나 무의미한 기호를 이용한다. 그 예로 Whitespace는 오직 공백 문자, 탭#s-3, 줄바꿈 문자만을 이용하므로 보통 텍스트 에디터에서는 제대로 읽기도 어렵다. 아희 코드는 무늬만 한글이지, 외계어가 따로 없다.
- 코드가 코드같지 않거나 표현이 과장되었다. Shakespeare는 겨우 "Hello, World!"를 출력하는데 코드가 50줄을 넘으며, Chef의 코드는 아예 레시피 형태이다. Dark는 중2병스럽게 표현을 과장시킨 예.
- 1차원이 아닌 자료 및 코드 영역을 사용한다. 극단적인 예로 NULL이라는 언어를 들 수 있는데, 이 언어는 0차원 프로그래밍 언어로 하나의 숫자가 하나의 프로그램이며 소인수분해를 통해 명령을 생성해낸다.[4] 이런 언어들은 대부분 유명한 esolang인 비펀지의 영향을 많이 받았다. 참고로 비펀지의 구조는 2차원 구조.
- 비결정적으로 동작한다. 즉, 경우에 따라 같은 프로그램이 다른 결과를 내놓는다. 대표적인 예는 Java2K나 Thue. NFA(비결정적 유한 오토마타 기계)의 컨셉을 활용한 것이 많다.
- 존재 자체가 더럽다. 프로그램의 작성이 거의 불가능할 정도로 어렵게 만든 언어가 대부분이다. Malbolge가 대표적인 예. 소개된 지 무려 2년 만에 첫 프로그램이 나왔을 정도로 악질이다.
- 반면 컴파일러나 인터프리터 등의 작성은 다른 고급 언어보다 오히려 쉬운 편이다. 일반적인 고급 언어는 대체로 구조가 복잡하기 때문에 번역기 작성이 어려운 편.
Esolang 위키에 정리된 각종 난해한 프로그래밍 언어로 작성된 Hello, world!
3. 예시
- A: 알파벳 A만으로 프로그램을 작성한다.
- A(위의 A와는 다르다!): 코드 전체가 난해한 특수문자라 치는 것과 쓰는 것 모두가 어렵다.
- ArnoldC: 아놀드 슈워제네거의 영화 속 명대사(One-liner)들로만 이루어진 언어. 예를 들어 Return 커맨드는 I'LL BE BACK, EqualTo는 YOU ARE NOT YOU YOU ARE ME, 그리고 False는 I LIED(...)다.
- asdf: 말 그대로
,a
,s
,d
의 4글자로 프로그래밍을 한다.f
- Dark: 명령어가 전부 부정적인 단어들로 대치되어 있다. 중2병 컨셉으로, traceon이라는 명령어는 게임 Fate/stay night의 주인공 에미야 시로에서 따온 것이다.
- DNA# : DNA와 염기구조를 모티브로 한 언어. 코드들은 대개 유전자 모양을 띈다.
- emojicode: 이모지를 사용한 언어.
- ETA#s-4: 영어에서 가장 많이 쓰이는 알파벳인
,E
,T
,O
,I
,A
,N
,S
를 명령어로 사용한다.H
- FiM++: My Little Pony: Friendship is Magic의 팬들에 의해 만들어진 언어로, 트와일라잇 스파클이 셀레스티아 공주에게 보내는 우정 보고서를 바탕으로 실제 편지글처럼 읽을 수 있는 것을 목적으로 한 언어다. 예를 들어서 편지의 수신자는 곧 클래스의 이름이 되고, Hello world!는
가 된다. Java의 문법을 자연어로 치환한 것이라 자바와 완벽하게 1:1 대응이 되도록 제작중이다. 특이하게 편지가 소스 코드라는 티가 나지 않도록 하나의 명령에 같은 뜻을 지닌 여러 개의 단어가 대응된다.[5] 인터프리터 및 샘플 코드는 여기를 참조.I said “Hello World”!
- Fugue: 이름처럼 실제 악보로 코드를 구현한다.
- GNE(그네)[6] : 박근혜 화법 및 그 외 사건사고를 기반으로 한 언어다. 아직 구현된 컴파일러는 없다. 또한 하드웨어 사양으로 CPU: 인텔 제온E7, 메모리: 486GB, 승마장, 독일 직통 광케이블(...)을 요구한다. 객체 지향에 문법이 거의 불규칙에 가깝고 식별자에는 띄어쓰기가 난무하는 것을 보면 구현이 더 난해할 듯 하다.
- Grass:
,W
,w
의 3종류의 알파벳만으로 프로그램을 작성한다. 코드가 풀밭처럼 보여서 이런 이름이 되었다고 한다.v
- 호무호무: 위의 Grass의 파생 언어.
를w
,ほむ
를 공백 문자,W
를 개행 문자로 치환한 것으로 보인다. 이 이전에도 또다른 파생 언어가 2개 있었다.v
- 호무호무: 위의 Grass의 파생 언어.
- HQ9+: 명령어가
,H
,Q
,9
이렇게 4개뿐이다. H는 "Hello, world!" 출력을, Q는 콰인[7] 을, 9는 99병의 맥주 가사 출력을, +는 가산기 1 증가를 담당한다. 물론, 이 언어로 제대로 된 프로그래밍은 불가능하다.(...)+
- Java2K: 비결정적으로 동작하는 프로그래밍 언어.
- Kvikkalkul
- LOLCODE: 비슷한 테마로 Omgrofl이 있다.
- Malbolge: 이쪽 계열의 끝판왕. 자세한 것은 해당 문서 참조.
- NULL: 본격 0차원 프로그래밍 언어. 그냥 양의 정수를 하나 쳐넣으면 그것 자체가 프로그램이 된다. 그 숫자를 소인수분해하는것을 통해서 명령을 만들어낸다!
- NVSPL2: 브레인퍽과 유사한 언어로, 국산이다. 명령어들이 죄다 한 글자로 이루어져 있지만 비교적 쉬운 축에 속한다.
- OISC: 단일 명령어 세트 컴퓨터(One Instruction Set Computer)의 약자로, 단 하나의 명령어만으로 튜링 완전하다. 이 짓거리가 가능한 명령어 중 가장 많이 구현되는
명령어의 정의는 다음과 같다.subleq
-
: 메모리 주소subleq(a, b, c)
에 있는 값에서 메모리 주소a
에 있는 값을 뺀 결과값을 메모리 주소b
에 저장한다(b
). 이 값이 0과 같거나 작으면 메모리 주소*b = *a - *b;
로 점프한다. 아니라면 다음 명령어를 실행한다.c
-
- ORK: 이름부터 패기가 넘친다. Objekts R Kool의 약자...라는데 대놓고 포자번식하는 어떤 우주 깡패들을 연상시킨다. 이름에서 보이듯이 객체지향 언어이며, 사실 소스 코드의 보이는 형태 자체는 오크들하고는 별 관련이 없다. C++로 번역하는 것도 가능한 듯 하다.
- PATH
- Piet: 데이비드 모건-마(David Morgan-Mar)란 사람이 몬드리안의 그림을 보고 만든 언어. 도트 노가다로 그림을 그리면 점의 위치와 RGB 값이 코드의 역할을 한다. "Hello, World!" 코드는 아래와 같이 짠다.[8]
[image]
RGB 값 중 실제로 프로그래밍 작동에 관여하는 색은 흰색, 검은색 포함 총 20개 뿐이고 나머지 색은 모두 흰색과 같은 역할이지만, 프로그래밍을 작동시키는 위치의 방향을 정하는 방법이 상당히 난해하다. 더 많은 코드는 여기서 볼 수 있다. 그 외에 이 언어와 브레인퍽을 합친듯한 Brainloller라는 물건도 있다.
RGB 값 중 실제로 프로그래밍 작동에 관여하는 색은 흰색, 검은색 포함 총 20개 뿐이고 나머지 색은 모두 흰색과 같은 역할이지만, 프로그래밍을 작동시키는 위치의 방향을 정하는 방법이 상당히 난해하다. 더 많은 코드는 여기서 볼 수 있다. 그 외에 이 언어와 브레인퍽을 합친듯한 Brainloller라는 물건도 있다.
- Pxem: 파일 이름이 코드의 역할을 한다. 파일 내용은 비어 있어도 된다.
- Sclipting: 한글과 한자, 일부 전각 특수문자를 활용해서 만든 난해한 프로그래밍 언어다. 개발자는 해당 위키의 Timwi라는 유저.
- Thue
- 브레인퍽:
의 8글자만으로 튜링 완전하다. 아래의 언어들은 모두 브레인퍽 기반의 파생 언어다.+-[]<>.,
- Runic : 룬 문자의 알파벳들을 명령어로 이용한 언어. 10부터 1까지 거꾸로 출력하려면
이렇게 해야한다. (...)ᚦᚦᚦᚦᚦᚦᚦᚦᚦᚦᚲᚠᛉᛚ
- Misa: 미사쿠라어로 프로그램을 작성한다. 현재 홈페이지 접속이 불가능하다.
- Ook!
- Nyaruko: 브레인퍽에서 각 명령어를 아스키 아트로 바꾼 것. 기어와라! 냐루코 양의 오프닝 太陽曰く燃えよカオス에서 아이디어를 얻었다고 한다.
-
: 포인터를 오른쪽으로 이동(」・ω・)」うー(/・ω・)/にゃー
-
: 포인터가 가리키는 수치를 1 증가(」・ω・)」うー!(/・ω・)/にゃー!
-
: 포인터를 왼쪽으로 이동(」・ω・)」うー!!(/・ω・)/にゃー!!
-
: 포인터가 가리키는 수치를 1 감소(」・ω・)」うー!!!(/・ω・)/にゃー!!!
-
: 포인터가 가리키는 수치가 0이라면 대응하는 'I WANNA CHAOS!'까지 점프한다.CHAOS☆CHAOS!
-
: 포인터가 가리키는 수치가 0이라면 대응하는 'CHAOS☆CHAOS!' 까지 점프한다.I WANNA CHAOS!
-
: 포인터가 가리키는 수치를 출력한다.Let's\(・ω・)/にゃー
-
: 입력하는 1바이트를 읽는다.cosmic!
-
- JapariProgrammingLanguage(자파리프로그래밍언어) - 브레인퍽 기반으로, 케모노 프렌즈(애니메이션 1기)를 모티브로 삼았다.
- Runic : 룬 문자의 알파벳들을 명령어로 이용한 언어. 10부터 1까지 거꾸로 출력하려면
- 비펀지: 2차원 공간 위에 코드를 작성한다. 자세한 내용은 해당 문서 참조.
- 셰익스피어 프로그래밍 언어: 코드를 셰익스피어의 희곡처럼 쓴다.
- 셰프: 레시피 형식으로 코드를 쓴다. 코더가 신경을 좀 쓰면 실제 활용 가능한 레시피로 작성할 수 있다!
- ㅇㅈ: 위의 HQ9+와 상당히 유사하다. 명령어는
,ㅇ
,ㅈ
뿐이다. 아희와 같이 한글로 된 언어다. 언어 명세ㅊ
-
:ㅇ
를 출력한다.안녕 세계
-
: 프로그램을 종료한다.ㅈ
-
: 비엄격 모드 전용.ㅊ
의 형식으로 문자열을 출력한다. 한글과 일부 숫자만 사용할 수 있다. 변환표는 위의 언어 명세를 참조.ㅊ(...)
-
- 아희: 국산 프로그래밍 언어. 한글만으로 프로그램을 작성한다. 위의 비펀지와 같이 2차원이다.
- 언람다
- 인터칼: 최초의 난해한 프로그래밍 언어.
- 혀엉...:
,형
,항
,핫
,흣
,흡
등 일부 한글 글자와 문장 부호흑
,.
,?
, 특수 문자로 코드를 작성하는 언어. 완성된 코드를 보면 뭔가 기분이 이상하다.!
예시로 Hello, world!는 이렇게 쓴다.
혀어어어어어어어엉........ 핫. 혀엉..... 흑... 하앗... 흐윽... 형. 하앙. 혀엉.... 하앙... 흐윽... 항. 항. 형... 하앙. 흐으윽... 형... 흡... 혀엉.. 하아아앗. 혀엉.. 흡... 흐읍... 형.. 하앗. 하아앙... 형... 하앙... 흐윽... 혀어어엉.. 하앙. 항. 형... 하앙. 혀엉.... 하앙. 흑... 항. 형... 흡 하앗. 혀엉..... 흑. 흣
- 화이트스페이스: 공백 문자, 탭, 엔터로만 코드를 작성한다. 즉, 눈에 보이지 않는다.
- Unicat : 고양이 관련 이모지를 포인터로 한 esolang.
- 엄랭(Umjunsik-lang) : "엄", "준", "식"과 "!.,~"만을 사용하는 언어이다.
- - 코드가 0과 1 뿐이므로 난해한 프로그래밍 언어는 맞지만, 이건 진짜로 쓰려고 만든 것. 실제로 모든 프로그래밍 언어는 최종적으로 이 기계어로 번역된다. 같은 맥락에서 어셈블리어도 현재 기준으로는 드럽게 어렵긴 해도 본 문서의 예시들에 해당되진 않는다. 무엇보다 이 둘은 활발히 쓰였고, 지금도 배울 사람은 배워야 한다.
3.1. 난해한 스타일
정상적인 언어를 사용해 난해하게 작성하는 것. 스파게티 코드 같이 그냥 실력이 없어서 어려워진건 해당되지 않는다.
- JSFuck: JavaScript에서 사용하는 문자 중
,[
,]
,(
,)
,!
만으로 완전한 자바스크립트 코드를 작성한다.+
- 역시 정상적인 언어인 C언어로 최대한 난해한 코드를 짜는 대회가 있다. IOCCC 문서 참고.
[1] 코드를 쓰기는 하는데 '''읽지를 못하니...'''[2] $$SKxy$$ = $$Ky(xy)$$ = $$y$$에서 $$SKx=I$$임을 보일 수 있다.[3] 여기서 말하는 구성이란 대수적 구조와는 관계없다. 모든 튜링 완전한(Turing-complete) 언어는 대수적으로 보면 결국 모두 동일한 구조다.[4] 괴델 넘버링을 응용한 것이다. 괴델은 괴델 베타 함수를 이용하여 inductive structure를 갖는 모든 클래스의 원소를 하나의 자연수로 표현하였고, 이를 이용하여 프로그램 뿐 아니라, 수학 증명 자체도 하나의 자연수로 표현하였다. 이러한 자연수로의 인코딩/디코딩을 이용하여 증명한 것이 불완전성 정리이다.[5] 셰익스피어 프로그래밍 언어도 자연어를 사용하지만, 아스키 한 글자를 출력하는 명령인
Speak your mind
가 수없이 반복되는 것을 볼 수 있다.[6] 'GNE'란 'GNE is Not Eligible'의 약자라고 한다.[7] 프로그램 자신의 소스코드를 화면에 문자열로 출력하는 것.[8] 아래 홈페이지의 예시에 이거 말고도 8개의 Hello World를 출력하는 방법이 더 있다.