일반화 퀸 생성기


19

도전

이 과제에서는 소스 언어 S대상 언어 를 지정합니다 T. 당신의 임무는 P언어로 다음 프로그램을 작성하는 것 S입니다. Q언어로 된 유효한 프로그램이 에 대한 T입력으로 제공 P되면 입력 및 출력을받지 않는 R언어로 T된 유효한 프로그램 Q(R), 즉 Q의 소스 코드에 적용된 프로그램이 출력 됩니다 R. 또한 답안으로 사소한 예제 프로그램 Q(더 흥미롭고 더 나은 점수를 얻지 만 더 우수합니다), 결과 프로그램 R및의 결과를 제시해야 R합니다. 이것은 코드 골프이므로 P승리를 위한 가장 짧은 코드입니다 .

다시 말해, 이것은 임의의 유형의 일반화 된 퀴를 생성 할 수있는 "유니버설 퀴 생성자"를 작성하는 것에 대한 도전입니다.

설명

  • 소스 언어와 대상 언어가 동일 할 수 있습니다.
  • 프로그램 P은 모든 출력 프로그램에서와 같이 하나의 문자열을 입력 (STDIN 또는 이와 동등한 것)으로, 하나의 문자열 (STDOUT 또는 동등한 것)을 출력해야합니다 R.
  • 입력 프로그램 Q도 문자열을 다른 문자열로 변환해야하지만 형식이 더 유연합니다. 문자열 대 문자열 함수, 특정 이름으로 변수를 수정하는 코드 스 니펫, 대상 언어 인 경우 데이터 스택을 수정하는 스니 펫일 수 있습니다. Q예를 들어 주석이 포함되어 있지 않을 수도 있음을 명시 하여의 형식을 추가로 제한 할 수 있습니다 . 그러나 계산 가능한 문자열 대 문자열 함수를 입력 프로그램으로 구현할 수 있어야하며 Q, 함수가 작동하는 방식과 추가 제약 조건을 명시 적으로 명시 해야 합니다.
  • 출력 프로그램 R은 실제로 (일반화 된) 퀴인이어야하며, 그렇지 않으면 입력 (사용자 입력, 파일 등)을 읽지 않아야합니다 Q.
  • 표준 허점 은 허용되지 않습니다.

소스 언어로 Python을 선택하고 대상 언어로 Haskell을 선택하고 입력 프로그램 String -> String이라는 함수 의 한 줄 정의 여야한다고 가정합니다 f. 문자열 역전 프로그램을 주면

f x = reverse x

내 파이썬 프로그램에 대한 입력으로 P다른 Haskell 프로그램의 소스 코드를 출력합니다 R. 이 프로그램은의 소스 코드를 STDOUT에 인쇄 R하지만 반전됩니다. 경우 P신원 기능을 부여

f x = x

입력으로, 출력 프로그램 R은 quine입니다.

답변:


7

소스 = 대상 = CJam, 19 17 16 바이트

{`"_~"+}`)q\"_~"

이것은 입력 프로그램 Q(STDIN에서 제공)이 스택의 맨 위에 문자열을 기대하고 스택의 맨 위에 다른 문자열을 남기는 CJam 스 니펫 이라고 가정합니다 .

여기에서 테스트하십시오.

  1. 신원은 빈 스 니펫 일 뿐이므로 STDIN을 빈 지문으로 남겨 두십시오.

    {`"_~"+}_~
    

    추가로 표준 quine +입니다.

  2. CJam에서 문자열을 되돌리려면을 사용할 수 W%있으므로 STDIN에 넣으면 다음과 같이 나타납니다.

    {`"_~"+W%}_~
    

    우리가 얻을 수있는

    ~_}%W+"~_"`{
    
  3. 세 번째 예로, 공백이있는 문자열을 산재하는 스 니펫을 사용한다고 가정 해 보겠습니다 ' *. P입력으로 실행 하면

    {`"_~"+' *}_~
    

    차례로 인쇄

    { ` " _ ~ " + '   * } _ ~  
    
  4. Q줄 바꿈 이 포함 된 경우에도 작동합니다 (CJam에서는 필요하지 않지만). 다음은 줄 바꿈이있는 프로그램으로, 문자열에서 모든 줄 바꿈을 제거합니다 (불필요하게 복잡한 방식으로 줄로 나눈 다음 조인).

    N/
    ""
    *
    

    결과는 다음과 같습니다 R.

    {`"_~"+N/
    ""
    *}_~
    

    차례로 인쇄

    {`"_~"+N/""*}_~
    

설명

먼저 생성 된 출력을 살펴 보겠습니다.

표준 CJam quine은

{`"_~"}_~

다음과 같이 작동합니다.

  • 블록을 미십시오 {`"_~"}.
  • 으로 복제하십시오 _.
  • 로 사본을 실행하십시오 ~.
  • 이제 블록 내부에서 `첫 번째 블록을 문자열 표현으로 바꿉니다.
  • "_~" 블록의 일부가 아닌 소스의 두 문자를 푸시하므로 문자열 표현에서 누락됩니다.
  • 두 문자열은 프로그램 끝에서 연속적으로 인쇄됩니다.

기본 quine에서는 `블록을 그대로두면 프로그램 끝에서 모두 동일하게 인쇄되므로 불필요합니다.

내 프로그램의 출력은 P이 스 니펫의 수정 된 버전입니다. 먼저 +블록 에 a 를 추가 하여 두 문자열을 전체 소스를 포함하는 하나의 문자열로 연결합니다. 이것은 블록 내부에서 무엇을하든 관계없이 사실입니다 `. 이제 단순히 프로그램 / 스 니펫을 Q블록 뒤에 넣어서 +소스 문자열을 인쇄하기 전에 수정할 수 있습니다. 다시 한 번 Q블록 내부로 들어가기 때문에 해당 소스 문자열의 일부가됩니다.

요약하면, P인쇄

{`"_~"+Q}_~

이제이 출력을 구성하는 방법에 대해 P:

{`"_~"+}         "Push the block without Q.";
        `        "Turn it into a string. This is shorter than writing a string right away,
                  because I'd have to escape the quotes, and I'd need two quotes instead of
                  one backtick.";
         )       "Pop off the last character (the brace) and push it on the stack.";
          q      "Read input Q.";
           \     "Swap Q with the brace.";
            "_~" "Push the final two characters.";

4 개의 문자열은 프로그램 끝에서 자동으로 (back-to-back) 인쇄됩니다.


1
글쎄, 이것은 빠르다! 그리고 확실히 이길 수 없습니다. 설명도 좋습니다.
Zgarb

W %가 반대로 바뀌는 것을 어디에서 배웠습니까? dl.dropboxusercontent.com/u/15495351/cjam.pdf 파일 이 없습니다
Faraz Masroor

더 완벽한 방법 목록이 있습니까?
Faraz Masroor

@FarazMasroor sourceforge.net/p/cjam/wiki/Basic%20operators/#percent (3 번) ... 이것은 GolfScript에서 빌린 기능이며 어떤 시점에서 누군가 그것이 GolfScript에서 어떻게 작동하는지 말해주었습니다. CJam / GS의 모든 사용자가 가지고있는 이상한 암묵적 지식이지만 실제로는 많은 곳에서 설명되지 않는 것은 일반적인 관용구 인 것 같습니다. (더하지 철저하게 문서화 된 운영을 참조 sourceforge.net/p/cjam/wiki/Operators을 )
마틴 청산

3

하스켈 표현식 → 하스켈 표현식, 41 바이트

((++)<*>show).('(':).(++")$(++)<*>show$")

온라인으로 사용해보십시오!

작동 원리

P $ "Q"= ((++)<*>show).('(':).(++")$(++)<*>show$") $ "Q"구조 "R"에 의해

  1. (++")$(++)<*>show$"): 문자열을 추가 ")$(++)<*>show$",
  2. ('(':): 문자 앞에 추가 '('하고
  3. (++)<*>show(= \x->x++show x) : 인용 된 버전을 추가하면

결과는 "R"= "(Q)$(++)<*>show$\"(Q)$(++)<*>show$\"".

R=에 (Q)$(++)<*>show$"(Q)$(++)<*>show$"의해 작동

  1. 문자열을 가지고 "(Q)$(++)<*>show$",
  2. (++)<*>show: 인용 된 버전을 추가하면,
  3. Q그것에 적용

결과는 Q "(Q)$(++)<*>show$\"(Q)$(++)<*>show$\""= Q "R".

(이와 같이 쉽게 포함 할 수 있고 불행히도 올바른 연관성이 Q있기 때문에 주변의 괄호 가 필요 Q합니다 .)$R$

데모

λ> putStrLn $ ((++)<*>show).('(':).(++")$(++)<*>show$") $ "id"
(id)$(++)<*>show$"(id)$(++)<*>show$"
λ> putStrLn $ (id)$(++)<*>show$"(id)$(++)<*>show$"
(id)$(++)<*>show$"(id)$(++)<*>show$"
λ> putStrLn $ ((++)<*>show).('(':).(++")$(++)<*>show$") $ "reverse"
(reverse)$(++)<*>show$"(reverse)$(++)<*>show$"
λ> putStrLn $ (reverse)$(++)<*>show$"(reverse)$(++)<*>show$"
"$wohs>*<)++($)esrever("$wohs>*<)++($)esrever(
λ> putStrLn $ ((++)<*>show).('(':).(++")$(++)<*>show$") $ "length"
(length)$(++)<*>show$"(length)$(++)<*>show$"
λ> print $ (length)$(++)<*>show$"(length)$(++)<*>show$"
44

다만이 $괄호가 필요하지만 뒤에 let, do또는 람다 식입니다.
Ørjan Johansen 2016

@ ØrjanJohansen 맞습니다.하지만 괄호로 묶지 않은 람다 / let/ if/ case/를 do직접 내 보내지 않으면 언어 하위 집합을 정의 할 수 있습니다 . 아마도 내가 할 필요는 없었을 것입니다.
Anders Kaseorg

2

소스 = 대상 = JavaScript, 66

console.log("function a(){console.log("+prompt()+"(a+'a()'))}a()")

Q에 대한 가정 :

  • Q 문자열 대 문자열 JavaScript 익명 함수 여야합니다.

예 :

  • 반전 . Q =function(s) { return s.split('').reverse().join(''); }

이 경우 P(Q)(또는 R)는 다음 function a(){console.log(function(s) { return s.split('').reverse().join(''); }(a+'a()'))}a())(a}))')(a'+a(} ;)''(nioj.)(esrever.)''(tilps.s nruter { )s(noitcnuf(gol.elosnoc{)(a noitcnuf같 으며 실행하면 다음과 같습니다 Q(R).

  • 정체성 . Q =function(s) { return s; }

이 경우, P(Q)(나 R)입니다 : function a(){console.log(function(s) { return s; }(a+'a()'))}a()A는 어떤 자바 스크립트 Quine . 말할 필요도없이 Q(R), Q는 아이덴티티 함수이기 때문에 동일 할 것입니다.


몇 가지 참고 사항 :

자바 스크립트의 STDIN은 전통적으로 prompt(), alert()복사 붙여 넣기를 사용하여 프롤로그로 실행 출력 프로세스를 수행하기 위해 STDOUT 이라는 전통을 자제 할 수있었습니다 . (로 변경 하면 최대 12자를 저장할 수 있습니다 alert().)

ES6에서도 훨씬 짧은 시간을 만들 수 있지만 현재는 기본 JavaScript를 유지하고 싶습니다. 나는 단지 경험을 위해 S = Scala, T = ECMA6 답변을 제출하는 것을 고려하고 있습니다.

또한 JavaScript는 에서 CJam 을 절대 능가하지 못한다는 것을 알고 있지만이 도전을해야했습니다! 분명히 재미있는 일이었습니다.


감사! 소스 및 대상 언어가 다른 항목을 사용하는 것이 좋습니다.
Zgarb

2

젤리7 , 9 바이트

“ṚƓ^ṾṂ’³3

온라인으로 사용해보십시오!

Q는 7 개의 함수 (즉, 최상위 스택 요소를 넘어 보지 않고 스택을 통해 I / O를 수행함)이며 명령 줄 인수로 제공됩니다.

설명

7 프로그램

여기서 사용하는 7의 범용 quine 생성자는 다음과 같습니다.

717162234430…3

가장 먼저 주목할 점은 선행 7은 선행 공백과 동일하며 프로그램에 영향을 미치지 않는다는 것입니다. 그것이 유일한 이유는 리터럴 전용 quine에 대한 PPCG의 규칙을 따르는 것입니다 ( 1프로그램 자체가 아니라 두 번째 코드로 인코딩 됨 ).

프로그램의 나머지 부분은 단일 스택 요소 ( 7s와 6s 가 균형을 이루고 있음 )이며 실행할 때 다음을 수행합니다.

717162234430…3
 1716           Push a stack element "7" onto the stack
     2          Copy it
      23        Pop and output one of the copies (selecting format 7)
        4430    Prepend it to the top of stack
             3  Output it

즉,이 스택 요소는 7출력 형식 7 (예 : "원본 코드와 동일한 인코딩을 사용하여 문자 그대로 인쇄"을 의미 함) 을 앞에 추가 하여 스택의 맨 위를 인쇄하는 프로그램 이므로 quines). 여기서 우리는 리터럴 7을 두 가지 목적 (출력 형식 및 선행 공백)에 재사용 할 수 있다는 것은 매우 운이 좋은 것입니다 . 분명히 final 바로 앞에 무언가를 삽입 하여 출력 과 출력이 아닌 +의 3함수를 출력 할 수 있습니다 . 직접 입력하십시오.77

이 스택 요소는 어떻게 자체 소스 코드를 얻습니까? 프로그램의 끝에 도달하면 eval기본적으로 최상위 스택 요소는 7 입니다. 그러나 실제로 프로세스의 스택에서 튀어 나오지 않았으므로 eval주도 된 스택 요소 리터럴 이 여전히 있습니다. (즉, 프로그램은 프로그램 7의 시작 부분을 리터럴의 일부가 아닌 스택 요소 구분 기호 로 볼 수 없다는 사실에서 알 수 있듯이 자체 소스를 읽지 않고 오히려 eval기본적으로 주도되는 리터럴로 구성됩니다 .)

젤리 프로그램

이것은 아마도 내가 작성한 가장 젤리와 같은 젤리 프로그램 중 하나 일 것입니다. 그것은 세 nilads (구성 “ṚƓ^ṾṂ’, ³, 3아무 작업도 그들에 수행되지 않기 때문에 시퀀스에서 바로 출력된다). 는 3단지 정수 상수 인 명백한 충분하다. 은 ³당신이 젤리를 알고있는 경우도 간단하다 : 그것은 (젤리는 일반적으로 자사의 입력을 받아 곳이다) 첫 번째 명령 줄 인수에 대한 젤리의 명시 적으로 표기합니다. Jelly 프로그램의 나머지 부분은 7 개의 보편적 인 quine 생성자를 나타냅니다. 7의 모든 명령이 ASCII 숫자를 사용하여 표현 될 수 있다는 사실을 이용함으로써717162234430일련의 명령이나 8 진수 (개념적으로와 같이)가 아니라 10 진수로 표시되므로 출력에 특별한 형식이 필요하지 않습니다. 이 10 진수 “ṚƓ^ṾṂ’는 Jelly의 압축 정수 표기법이됩니다.

24053프로그램 Q를 제공 하면 다음과 같은 결과가 나타납니다.

717162234430240533

온라인으로 사용해보십시오!

2405 상단 스택 요소를 자체에 연결합니다.

2405   Stack   Explanation
       x
2      x|x     Duplicate top of stack
 4     x||x    Swap two stack elements, with an empty element between
  0    x|(X)   Escape the top stack element, then concatenate the top two
   5   xx      Execute the top stack element

(마지막 단계는 약간 혼란스러워 보일 수 있습니다. 발생하는 일은 스택 요소를 이스케이프하면 각 명령이 "이 명령 실행"에서 "이 명령을 스택 맨 위에 추가"로 변환되므로 각 명령이 원래 명령에 추가됩니다. 최상위 스택 요소가 실행될 때

따라서 결과 프로그램 R을 실행하면 두 개의 R 사본이 제공됩니다.

7171622344302405371716223443024053

2

CJam → CJam, 13 바이트

{`"_~"+7}_~qt

온라인으로 사용해보십시오!

입력 Q은 스택의 유일한 문자열을 수정하는 코드 스 니펫이어야합니다. Qstdin에서 읽습니다.

입력:

S*W%

두 문자 사이에 공백을 추가하고 문자열을 반대로 바꿉니다.

산출:

{`"_~"+S*W%}_~

일반화 된 quine의 출력 :

~ _ } % W * S + " ~ _ " ` {

설명

{`"_~"+7}_~      e# Evaluate a generalized quine in CJam that only appends a 7.
q                e# Read the input.
t                e# Replace the 7th character (0-based) with the input.

먼저 quine을 평가하므로 불필요한 큰 따옴표없이 문자열 표현을 얻을 수 있습니다. 그런 다음 페이로드를 입력으로 교체하십시오.

{`"_~"+ }_~7qt공간이 페이로드의 자리 표시 자일 수 있습니다 . 그러나 페이로드를 변경하면 7바이트 가 절약됩니다.


1

Perl (5), 29 33 바이트

A$_=q(αA);evalβαS"\α$_β\n";printβ

온라인으로 사용해보십시오!

Perl 프로그램 Q는 입력을 오른쪽으로 문자열로 가져와 변수에 출력을 제공하는 스 니펫을 리턴해야합니다 $_. (임의 Perl 함수는로 래핑하여이 형식으로 변환 할 수 있습니다 sub x {…}; $_=x. 그러나 대부분의 경우 Perl의 구문은 래핑이 필요하지 않음을 의미합니다.)

설명

범용 Perl quine 생성자는 다음과 같습니다.

$_=q(…"\$_=q($_);eval";print);eval

(대부분의 경우이 골프장까지 골프를 원 $_=q(say…"\$_=q($_);eval");eval하지만 임의의 Perl 코드를 거기에 넣을 수 있는지 확실하지 않습니다 .)

다시 말해, $_=q(…);eval문자열을 할당 한 $_다음 평가 하는 외부 래퍼 가 있습니다. 래퍼 안에는 "\$_=q($_);eval"즉, 우리가 저장 한 값 $_과 사용자가 지정한 코드 Q 를 사용하여 내용과 함께 래퍼를 재구성 print하고 출력을 인쇄합니다. (불행히도 우리는 사용할 수 없습니다say ; 개행을 추가하며 이는 quines와 관련이 있습니다.)

이 답변의 "포인트"는 Perl에서 일반화 된 quines을 생성하는 것이 었습니다. 일단 그 전략을 수행하기위한 골프 전략 (다른 많은 답변에 사용 된 전략)을 가지고 나면 프로그램 P를 작성할 때가되었습니다. 템플릿에 문자열. 내가 원했던 것은 상수 문자열을 인쇄하고 (이상적으로 압축), 사용자 입력을 보간하는 데 도움이되는 언어였습니다.

몇 가지를 시도한 후에, 나는 이전에 사용하지 않은 (그리고 실제로는 일부 문서로 할 수있는) Charcoal에 정착했습니다. ASCII 예술을 위해 설계되었지만 한 차원에서 문자열을 쓸 수도 있습니다. ASCII 문자는 문자 적으로 Charcoal로 인쇄됩니다. 즉, 상수 문자열을 인쇄 할 때 상용구를 사용하지 않으며 명령을 사용하여 사용자 입력에서 가져온 문자열을 프로그램에 보간 할 수 있습니다 .

그래도 (약간) 짧아 질 수 있습니다. Perl 범용 퀴 생성자에는 상당히 긴 반복 섹션이 2 개 있습니다. 따라서 명령을 사용하여 변수에 변수를 할당 할 수 있습니다 (예 : 변수에 A…α할당)α ) 변수를 이름을 사용하여 인쇄중인 문자열에 보간 할 수 있습니다. 문자 그대로 문자열을 쓰는 것보다 몇 바이트를 절약합니다.

불행히도 Charcoal은 프로그램에 개행을 추가하지만 그다지 큰 문제는 아닙니다. \nQ의 입력에 개행을 추가하는 데 2 바이트가 필요합니다 .

입력 $_=reverse(문자열을 반대로)을 주면 다음과 같은 출력을 얻습니다.

$_=q($_=reverse"\$_=q($_);eval\n";print);eval

온라인으로 사용해보십시오!

예상대로 소스를 거꾸로 인쇄하는 유사합니다.


1

젤리언더로드 , 15 바이트

“(a(:^)*“S):^”j

온라인으로 사용해보십시오!

입력 언더로드 함수 Q를 명령과 같은 인수로 사용합니다. Q는 더 깊은 스택 요소를 검사하지 않고 스택에서 입력을 가져 와서 출력을 스택으로 푸시해야합니다.

설명

언더로드

여기서 사용되는 Underload 범용 퀴네 생성자는 다음과 같습니다.

(a(:^)*…S):^

대부분의 프로그램은 단일 리터럴입니다. 우리는 :^그것을 복사하여 복사 한 다음 한 사본을 평가합니다 (다른 사본을 스택에 남겨 둡니다).

리터럴이 평가를 시작하면 a(이스케이프하여 원래 프로그램과 같은 형태로 다시 가져옵니다) 및 (:^)*(첨부 :^)를 실행하여 전체 프로그램의 소스 코드를 재구성합니다. 그런 다음 함수 Q를 실행하여이를 임의의 방식으로 변환하고 결과를S .

젤리

프로그램이 줄 바꿈으로 끝나는 경우 유효성 검사 언더로드 인터프리터가 프로그램 끝에서 충돌하기 때문에 이번에는 숯을 사용할 수 없습니다. (TIO와 같은 일부 Underload 통역사는이 규칙을 시행하지 않지만 제대로 이식하고 싶었습니다.) 불행히도 Charcoal은 출력에 마지막 줄 바꿈을 자연스럽게 추가합니다. 대신, 나는 Jelly를 사용했는데, 이것은 이와 같은 간단한 경우에 거의 간결합니다. 프로그램은 두 개의 요소 ( ““”) 가있는 목록 리터럴로 구성되며 입력 ( j)에서 결합하여 사용자 입력을 프로그램에 보간합니다.

입력 :S^(사본을 인쇄 한 다음 원본을 평가)을 사용하여 다음과 같은 언더로드 프로그램을 얻습니다.

(a(:^)*:S^S):^

온라인으로 사용해보십시오!

이것은 일반적인 흥미 진진한 행동을 한 후에 eval출력 된 내용의 사본에서 실행 됩니다. 그러면 전체 재구성 된 프로그램이 무한정 다시 실행됩니다 (언로드는 테일 재귀입니다). 실제로 자신을 꾸미고 행동하는 eval것은 실제로 Underload에서 무한 루프를 수행하는 유일한 방법입니다.


숯은 더 이상 후행 줄 바꿈을 추가하지 않습니다 (yay)
ASCII 전용

1

RProgN 2 , 11 바이트

'{`{.%s}{'F

프로그램 설명

'{`{.%s}{'F
'{`{.%s}{'  # Push the string "{`{.%s}{" to the stack.
          F # Format the input with the top of the stack as a template. Which produces {`{.<INPUT>}{

Quin Explination

생성 된 quine은 단순하지만 RProgN2에서 일치하지 않는 함수 처리기의 기능을 사용하여 "루핑"quine이라고하는 짧고 달콤한 quine을 만듭니다. <> <quine과 놀랍게 유사한 개념입니다.

{`{.}{
{`{.}   # Push the function {`{.} to the stack.
     {  # Try to define a new function, fail, loop back to index 1. (Which in turn, skips the function definition.)
 `{     # Push the string "{" to the stack.
   .    # Concatenate the top two values of the stack, which stringifies the function, then appends { to it.
    }   # Try to terminate a function, fail quietly, and terminate the program.

물론,이 quine의 구조로 인해 연결 기능 뒤에 진정한 no-ops (문자열이 지정되지 않은) 이외의 것을 배치 할 수 있습니다.

일부 quines

  • {`{.i}{: 출력 {}i.{`{. i"역"기능 일 뿐이므로이 프로그램은 자체적으로 출력됩니다.
  • {`{.S§.}{: 출력 ..S`{{{}§. S문자열을 문자 스택으로 변환하고 §스택을 사전 순으로 정렬 한 다음 .다시 결합하여 정렬합니다.

온라인으로 사용해보십시오!

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.