콰인 (전산학)

위키백과, 우리 모두의 백과사전.

콰인(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]);
  }
}

외부 링크[편집]