콰인 (컴퓨팅)


콰인(quine)은 입력 없이 자기자신의 소스 코드를 출력하는 프로그램이다. 이는 메타프로그램의 일종이며, 간접 자기 참조에 대해 광범위하게 연구한 윌러드 밴 오먼 콰인의 이름을 따서 명명되었다. 클레이니의 재귀 정리에 따르면, 계산가능한 문자열을 출력할 수 있는 프로그래밍 언어가 있다면 이 언어로부터 콰인을 만들 수 있다.
여기서 별도의 입력(사용자로부터의 입력이나, 파일 시스템 접근 등)을 필요로 하는 프로그램은 콰인으로 인정하지 않는다. 이를 인정할 경우 사용자에게 소스 코드를 입력하도록 요구하거나, 파일 시스템으로부터 코드를 읽어서 자기 자신을 출력할 수 있을 것이다. 몇몇 프로그래밍 언어에서는 아무것도 들어 있지 않은 소스 코드를 인정하기도 하지만 이 또한 자명하기 때문에 콰인으로 인정하지 않는다. 이러한 빈 프로그램은 IOCCC에서 한 번 ‘최악의 규칙 위반’이라는 이름으로 수상하기도 했으며, 그 뒤로는 빈 프로그램을 인정하지 않도록 규칙이 바뀌었다.
배경
[편집]이러한 "스스로를 재생산하는 오토마타"의 존재에 관해서는, 본래 1940년대 즈음에 존 폰 노이만이 universal constructor와 같은 형태를 이론화한 바 있다. 콰인 프로그램의 아이디어는 폴 브래틀리(Paul Bratley)와 쟝 밀로(Jean Millo)의 Computer Recreations; Self-Reproducing Automata에서 처음 등장했는데, 브래틀리는 1960년대에 아틀라스 오토코드로 쓰여진 다음 프로그램을 보고 자기 자신을 출력하는 프로그램에 관심을 가지게 되었다고 한다.
%BEGIN !THIS IS A SELF-REPRODUCING PROGRAM %ROUTINESPEC R R PRINT SYMBOL(39) R PRINT SYMBOL(39) NEWLINE %CAPTION %END~ %CAPTION %ENDOFPROGRAM~ %ROUTINE R %PRINTTEXT ' %BEGIN !THIS IS A SELF-REPRODUCING PROGRAM %ROUTINESPEC R R PRINT SYMBOL(39) R PRINT SYMBOL(39) NEWLINE %CAPTION %END~ %CAPTION %ENDOFPROGRAM~ %ROUTINE R %PRINTTEXT ' %END %ENDOFPROGRAM
예제
[편집]다음은 C로 짠 전통적인 콰인의 예이다. 이 프로그램은 ASCII 문자 집합을 사용해야 정상적으로 작동한다.
#include <stdio.h>
char S[] = "#include <stdio.h>%cchar S[] = %c%s%c;%cint main() { printf(S, 10, 34, S, 34, 10); return 0; }";
int main() { printf(S, 10, 34, S, 34, 10); return 0; }
여기서는 printf 함수의 포맷 문자열과 포맷 인자에 같은 문자열을 넣어서 S의 내용물을 출력하는 방법을 사용했다. 이 경우 C에서 탈출 문자로 사용하는 역슬래시(\)가 들어 갈 때 간단히 출력하기 힘들기 때문에, 10, 34와 같이 ASCII 문자 번호를 그대로 써서 역슬래시를 피하고 있다.
다음은 자바로 짠 콰인 프로그램의 한 예시이다.
public class Quine
{
public static void main(String[] args)
{
char q = 34;
String[] l = {
"public class Quine",
"{",
" public static void main(String[] args)",
" {",
" char q = 34;",
" String[] l = {",
" ",
" };",
" for(int i = 0; i < 6; i++)",
" System.out.println(l[i]);",
" for(int i = 0; i < l.length; i++)",
" System.out.println(l[6] + q + l[i] + q + ',');",
" for(int i = 7; i < l.length; i++)",
" System.out.println(l[i]);",
" }",
"}",
};
for(int i = 0; i < 6; i++)
System.out.println(l[i]);
for(int i = 0; i < l.length; i++)
System.out.println(l[6] + q + l[i] + q + ',');
for(int i = 7; i < l.length; i++)
System.out.println(l[i]);
}
}