Uogólniony generator Quine


19

Wyzwanie

W tym wyzwaniu określasz język źródłowy S i docelowy T . Twoim zadaniem jest napisanie następującego programu Pw języku S. Jeśli jako program wejściowy podano poprawny program Qw języku , wyświetli on prawidłowy program w języku, który nie przyjmuje danych wejściowych i wyjściowych , to znaczy program zastosowany do kodu źródłowego . Ponadto powinieneś przedstawić w swojej odpowiedzi nietrywialny przykładowy program (im bardziej interesujący, tym lepszy, choć nie zdobywasz za to punktów), wynikowy program i wynik działania . To jest kod-golf, więc najkrótszy kod wygranych.TPRTQ(R)QRQRRP

Innymi słowy, jest to wyzwanie związane z napisaniem „uniwersalnego konstruktora quine”, który może tworzyć dowolne typy uogólnionych quines.

Wyjaśnienia

  • Twoje języki źródłowe i docelowe mogą być identyczne.
  • Program Ppowinien pobrać jeden ciąg jako dane wejściowe (z STDIN lub równoważnego) i wyprowadzić jeden ciąg (do STDOUT lub równoważnego), tak jak każdy program wyjściowy R.
  • Programy wejściowe Qpowinny także przekształcać ciąg znaków na inny, ale ich forma jest bardziej elastyczna: mogą to być funkcje ciąg-ciąg, fragmenty kodu modyfikujące zmienną o określonej nazwie, fragmenty modyfikujące stos danych, jeśli język docelowy ma jeden itp. Możesz także dodatkowo ograniczyć formę tych Qplików, stwierdzając, że na przykład nie mogą one zawierać żadnych komentarzy. Jednak musisz być w stanie zaimplementować dowolną obliczalną funkcję typu string-to-string jako program wejściowy Qi musisz wyraźnie określić, jak one działają i jakie dodatkowe ograniczenia na nich nakładasz.
  • Program wyjściowy Rpowinien być naprawdę (uogólnionym) quine, więc nie może czytać żadnych danych wejściowych (danych wejściowych użytkownika, plików itp.), Chyba Qże tak się stanie.
  • Standardowe luki są niedozwolone.

Przykład

Załóżmy, że wybrałem Python jako język źródłowy i Haskell jako język docelowy, a ponadto wymagam, aby program wejściowy był definicją String -> Stringfunkcji o jednym wierszu f. Jeśli dam program do odwracania łańcucha

f x = reverse x

jako dane wejściowe do mojego programu Python P, wypisze kod źródłowy innego programu Haskell R. Ten program wypisuje do STDOUT kod źródłowy R, ale jest odwrócony. Jeśli Ppodano funkcję tożsamości

f x = x

jako wejście program wyjściowy Rjest quine.

Odpowiedzi:


7

Źródło = Cel = CJam, 19 17 16 bajtów

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

Zakłada się, że program wejściowy Q(podany na STDIN) to fragment kodu CJam, który oczekuje ciągu na górze stosu i pozostawia kolejny ciąg na szczycie stosu.

Sprawdź to tutaj.

Przykłady

  1. Tożsamość byłaby tylko pustym fragmentem, więc pozostawiając STDIN puste odciski

    {`"_~"+}_~
    

    Który jest standardowym quine, z dodatkowym +.

  2. Aby odwrócić ciąg w CJam, możesz użyć W%, więc umieszczając go na STDIN, daje to:

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

    które możemy uruchomić, aby uzyskać

    ~_}%W+"~_"`{
    
  3. Jako trzeci przykład, że używamy fragment, który przeplata ciąg ze spacjami: ' *. Używając Ptego jako danych wejściowych, otrzymujemy

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

    który z kolei drukuje

    { ` " _ ~ " + '   * } _ ~  
    
  4. Teraz działa również, jeśli Qzawiera podziały wierszy (chociaż nigdy nie jest to konieczne w CJam). Oto program z podziałem wiersza, który usuwa wszystkie podziały wiersza z łańcucha (w niepotrzebnie skomplikowany sposób - podziel się na linie, a następnie połącz):

    N/
    ""
    *
    

    Powoduje to R:

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

    który z kolei drukuje

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

Wyjaśnienie

Najpierw spójrzmy na wyprodukowane wyjście:

Standardowa Quine CJam to

{`"_~"}_~

Działa w następujący sposób:

  • Naciśnij blok {`"_~"}.
  • Powiel to za pomocą _.
  • Wykonaj kopię za pomocą ~.
  • Teraz wewnątrz bloku `zamienia pierwszy blok w jego ciąg znaków.
  • "_~" wypycha dwa znaki źródła, które nie są częścią bloku (a zatem nie ma ich w reprezentacji ciągu).
  • Dwa ciągi znaków są drukowane jeden po drugim na końcu programu.

W podstawowej quinie `jest to niepotrzebne, ponieważ jeśli po prostu opuścisz blok w niezmienionej postaci, zostanie wydrukowany tak samo na końcu programu.

Dane wyjściowe mojego programu Pto zmodyfikowana wersja tego fragmentu kodu. Najpierw dodałem a +do bloku, który łączy dwa ciągi w jeden ciąg zawierający całe źródło. Zauważ, że będzie to prawdą bez względu na to, co zrobię wewnątrz bloku, ponieważ wszystko to zostanie dodane do reprezentacji ciągu uzyskanej za pomocą `. Teraz mogę po prostu umieścić program / snippet Qwewnątrz bloku po +, aby mógł zmodyfikować ciąg źródłowy przed wydrukowaniem. Ponownie, ponieważ Qwchodzi do bloku, będzie częścią wspomnianego ciągu źródłowego.

Podsumowując, Pdrukuje

{`"_~"+Q}_~

A teraz, jak mam zamiar zbudować ten wynik w 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.";

Cztery ciągi są drukowane automatycznie (jedna po drugiej) na końcu programu.


1
To było szybkie! I z pewnością ciężko pobić. Wyjaśnienie też jest miłe.
Zgarb

Gdzie dowiedziałeś się, że W% się odwraca? dl.dropboxusercontent.com/u/15495351/cjam.pdf nie ma go
Faraz Masroor,

Czy istnieje pełniejsza lista metod?
Faraz Masroor,

@FarazMasroor sourceforge.net/p/cjam/wiki/Basic%20operators/#percent (nr 3) ... jest to funkcja zapożyczona z GolfScript iw pewnym momencie ktoś mi powiedział, że tak to działa w GolfScript. Wydaje się być tak powszechnym idiomem, że jest to jakaś dziwna ukryta wiedza, którą posiada każdy użytkownik CJam / GS, ale która w rzeczywistości nie jest wyjaśniona w wielu miejscach. (Aby uzyskać więcej, nie do końca udokumentowanych operatorów, patrz sourceforge.net/p/cjam/wiki/Operators )
Martin Ender

3

Wyrażenia Haskell → Wyrażenia Haskell, 41 bajtów

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

Wypróbuj online!

Jak to działa

P $ "Q"= ((++)<*>show).('(':).(++")$(++)<*>show$") $ "Q"konstruuje "R"przez

  1. (++")$(++)<*>show$"): dołączanie ciągu ")$(++)<*>show$",
  2. ('(':): poprzedzanie postaci '('oraz
  3. (++)<*>show(= \x->x++show x): dołączając cytowaną wersję tego,

powodując "R"= "(Q)$(++)<*>show$\"(Q)$(++)<*>show$\"".

R= (Q)$(++)<*>show$"(Q)$(++)<*>show$"działa według

  1. biorąc sznurek "(Q)$(++)<*>show$",
  2. (++)<*>show: dołączając cytowaną wersję tego,
  3. stosując się Qdo tego,

powodując Q "(Q)$(++)<*>show$\"(Q)$(++)<*>show$\""= Q "R".

(Parens wokół Qsą konieczne, ponieważ Qmogą zawierać $tak samo łatwo, jak to Rrobi, i $niestety są odpowiednio skojarzone).

Próbny

λ> 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

Nie tylko $wymaga nawiasów, ale również spływu let, dolub wyrażeń lambda.
Ørjan Johansen

@ ØrjanJohansen Racja, ale mógłbym zdefiniować podzbiór języka, który nie zezwala na niepodzielną lambda / let/ if/ case/, dojeśli sam ich nie wyemituję. Być może równie dobrze, że nie musiałem.
Anders Kaseorg

2

Źródło = Cel = JavaScript, 66

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

Założenia dla Q:

  • Q powinna być anonimową funkcją JavaScript typu string-to-string.

Przykłady:

  • Do tyłu . Q =function(s) { return s.split('').reverse().join(''); }

W tym przypadku P(Q)(lub R) będzie:, function a(){console.log(function(s) { return s.split('').reverse().join(''); }(a+'a()'))}a()a po jego wykonaniu otrzymamy: )(a}))')(a'+a(} ;)''(nioj.)(esrever.)''(tilps.s nruter { )s(noitcnuf(gol.elosnoc{)(a noitcnufco jest dokładnie takie samo jak Q(R).

  • Tożsamość . Q =function(s) { return s; }

w tym przypadku P(Q)(lub R) będzie: function a(){console.log(function(s) { return s; }(a+'a()'))}a()który jest Quine JavaScript . Nie trzeba dodawać, że Q(R)będzie to samo, ponieważ Q jest funkcją tożsamości.


Niektóre uwagi:

STDIN w JavaScript jest tradycyjnie prompt(), jednak pozwoliłem sobie powstrzymać się od tradycji alert()jako STDOUT, aby ułatwić uruchamianie wyjścia jako progrem przy użyciu kopiuj-wklej. (Zdaję sobie sprawę, że mogę zapisać do 12 znaków po zmianie na alert()).

Mogę także znacznie skrócić czas działania w ES6, ale na razie chcę pozostać przy Native JavaScript. Rozważam przesłanie w przyszłości odpowiedzi S = Scala, T = ECMA6, tylko dla doświadczenia.

Zdaję sobie również sprawę, że JavaScript prawie nigdy nie pokonuje CJam w , ale musiałem podjąć to wyzwanie! To było naprawdę zabawne.


Dzięki! Byłoby naprawdę fajnie mieć wpis z innymi językami źródłowymi i docelowymi.
Zgarb

2

Galaretka7 , 9 bajtów

“ṚƓ^ṾṂ’³3

Wypróbuj online!

Q jest funkcją 7 (tj. Która nie wykracza poza górny element stosu i wykonuje operacje wejścia / wyjścia przez stos) i jest podana jako argument wiersza poleceń.

Wyjaśnienie

Program 7

Uniwersalny konstruktor quine w 7, którego tu używam, to:

717162234430…3

Pierwszą rzeczą, na którą należy zwrócić uwagę jest to, że wiodące 7 jest odpowiednikiem wiodących białych znaków i nie ma żadnego wpływu na program. Jedynym powodem, dla którego istnieje, jest przestrzeganie reguł PPCG przeciwko literalnym literom (jest zakodowane przez sekundę 1w programie, a nie przez siebie).

Reszta programu jest pojedynczym elementem stosu (ma zbilansowane 7si 6s), który wykonuje następujące czynności po uruchomieniu:

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

Innymi słowy, ten element stosu jest programem, który drukuje górę stosu, z przygotowanym 7wyprzedzeniem, w formacie wyjściowym 7 (co oznacza „drukuj dosłownie, używając tego samego kodowania co kod źródłowy”, a zatem jest zdecydowanie najlepszym kodowaniem dla Quines). Jest to na szczęście szczęście, że możemy ponownie użyć literału 7do dwóch celów (format wyjściowy i wiodące białe znaki). Oczywiście, wstawiając coś tuż przed końcem 3, możemy wyprowadzić funkcję 7+ danych wejściowych, a nie tylko danych wyjściowych 7i wejście bezpośrednio.

W jaki sposób ten element stosu otrzymuje własny kod źródłowy? Po osiągnięciu końca programu evaldomyślnie górny element stosu wynosi 7 sekund. Jednak w rzeczywistości nie wyskakuje ze stosu, więc dosłownie element stosu, który był evalprowadzony, wciąż tam jest. (Innymi słowy, program nie odczytuje własnego źródła - o czym świadczy fakt, że nie jest w stanie zobaczyć 7na początku programu, który jest separatorem elementów stosu, a nie częścią literału - ale raczej składa się głównie z literału, który evaldomyślnie jest prowadzony).

Program galaretki

Jest to być może jeden z najmniej podobnych do Jelly programów Jelly, które napisałem; składa się ona z trzech nilads ( “ṚƓ^ṾṂ’, ³, 3), które są po prostu wyjście w kolejności, ponieważ żadne operacje są wykonywane na nich. Jest 3to dość oczywiste, po prostu bycie stałą całkowitą. Jest ³to również proste, jeśli znasz Jelly: to wyraźna notacja Jelly dla pierwszego argumentu wiersza poleceń (w którym Jelly zwykle bierze swój wkład). Reszta programu Jelly reprezentuje większość mojego 7 uniwersalnego konstruktora quine: wykorzystując fakt, że wszystkie polecenia w 7 można przedstawić za pomocą cyfr ASCII, możemy zinterpretować717162234430nie jako seria poleceń, a nawet jako liczba ósemkowa (tak jak jest koncepcyjnie), ale jako liczba dziesiętna, co oznacza, że ​​nie potrzebujemy żadnego specjalnego formatowania danych wyjściowych. Ta liczba dziesiętna staje się “ṚƓ^ṾṂ’w skompresowanym zapisie liczb całkowitych Jelly.

Przykład

Jeśli podamy 24053jako program Q, otrzymamy następujące dane wyjściowe:

717162234430240533

Wypróbuj online!

2405 łączy element najwyższego stosu z samym sobą:

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

(Ostatni krok może wydawać się trochę mylący; dzieje się tak, że ucieczka elementu stosu konwertuje każde polecenie w nim z „uruchom to polecenie” na „dołącz to polecenie na górze stosu”, więc każde polecenie dołącza się do oryginału element najwyższego stosu podczas działania).

W związku z tym uruchomienie wynikowego programu R daje nam dwie kopie R:

7171622344302405371716223443024053

2

CJam → CJam, 13 bajtów

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

Wypróbuj online!

Dane wejściowe Qpowinny być fragmentem kodu, który modyfikuje jedyny ciąg w stosie. Qjest czytane ze standardowego wejścia.

Przykład

Wejście:

S*W%

Dodaje spację między dwoma znakami i odwraca ciąg.

Wynik:

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

Dane wyjściowe uogólnionego quine:

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

Wyjaśnienie

{`"_~"+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.

Najpierw ocenia quine, dzięki czemu możemy uzyskać jego ciąg znaków bez zbędnych podwójnych cudzysłowów. Następnie zamień ładunek na dane wejściowe.

Może to być miejsce, w {`"_~"+ }_~7qtktórym przestrzeń jest symbolem zastępczym ładunku. Ale zmiana ładunku w celu 7zaoszczędzenia bajtu.


1

Węgiel drzewnyPerl (5), 29 33 bajtów

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

Wypróbuj online!

Program Perla Q powinien zwrócić fragment kodu, który pobiera dane wejściowe jako ciąg znaków po swojej prawej stronie i udostępnia dane wyjściowe w zmiennej $_. (Arbitralne funkcje Perla można przekonwertować na tę formę, pakując je jako sub x {…}; $_=x. W większości przypadków jednak składnia Perla oznacza, że ​​nie jest wymagane zawijanie).

Wyjaśnienie

The Perl

Oto jak wygląda uniwersalny konstruktor quinu dla Perla:

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

(W większości przypadków chciałbyś zagrać w golfa do tego stopnia $_=q(say…"\$_=q($_);eval");eval, ale nie jestem pewien, czy możesz tam wstawić dowolny kod Perla .)

Innymi słowy, mamy zewnętrzne opakowanie, $_=q(…);evalktóre przypisuje ciąg, $_a następnie go ocenia. Wewnątrz opakowania znajduje "\$_=q($_);eval"się rekonstrukcja opakowania wraz z jego zawartością za pomocą wartości, którą zapamiętaliśmy $_, oraz kodu Q określonego przez użytkownika oraz printdo wydrukowania wyniku. (Niestety nie możemy tego użyć say; dodaje nową linię i ma to znaczenie w quinesach).

Węgiel drzewny

„Istotą” tej odpowiedzi było stworzenie uogólnionych quinesów w Perlu, więc kiedy już miałem do tego strategię gry w golfa (której użyłem w wielu innych odpowiedziach), nadszedł czas, aby napisać program P, który w zasadzie po prostu zastępuje ciąg do szablonu. Chciałem tutaj języka, który był dobry w drukowaniu ciągów ciągłych (najlepiej trochę je kompresując) i interpolowaniu danych wejściowych użytkownika.

Po wypróbowaniu kilku, zdecydowałem się na węgiel drzewny, którego nigdy wcześniej nie używałem (i który naprawdę mógłby zrobić z pewną dokumentacją); jest zaprojektowany dla sztuki ASCII, ale może również pisać ciągi w jednym wymiarze. Znaki ASCII są drukowane dosłownie na węglu drzewnym, co oznacza, że ​​drukowanie ciągów ciągów nie wymaga płyty kotłowej i możemy użyć polecenia do interpolacji ciągu pobranego z danych wprowadzonych przez użytkownika do programu.

Można jednak (nieco) skrócić. Uniwersalny konstruktor quine Perla zawiera dwie dość długie powtarzające się sekcje. Możemy zatem użyć polecenia, aby przypisać je do zmiennych (np. A…αPrzypisuje do zmiennej α) i po prostu interpolować zmienne w ciągu, który drukujemy, używając ich nazw. To oszczędza kilka bajtów po prostu dosłownie napisując ciąg.

Niestety, węgiel drzewny dodaje także nowy wiersz do programu, ale to nie jest wielka sprawa; \ndodanie tego nowego wiersza do wejścia Q również kosztuje dwa bajty .

Przykład

Jeśli podamy dane wejściowe $_=reverse(które odwracają ciąg), otrzymamy następujące dane wyjściowe:

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

Wypróbuj online!

który jest podobny do quine, który drukuje swoje źródło wstecz, zgodnie z oczekiwaniami.


1

GalaretkaNiedociążenie , 15 bajtów

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

Wypróbuj online!

Pobiera wejściową funkcję niedociążenia Q jako argument podobny do polecenia. Q musi pobierać dane wejściowe ze stosu i przekazywać dane wyjściowe na stos, bez próby sprawdzania głębszych elementów stosu (ponieważ nie będą one istnieć).

Wyjaśnienie

Niedociążenie

Zastosowany tutaj uniwersalny konstruktor quine Underload to:

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

Większość programu jest dosłowna. Śledzimy to przez:^ , który go kopiuje, a następnie ocenia jedną kopię (pozostawiając drugą kopię na stosie).

Kiedy literał zaczyna się oceniać, uruchamiamy a(escape, który przywraca go do tej samej postaci, co oryginalny program A) i (:^)*(który dołącza :^), rekonstruując w ten sposób kod źródłowy całego programu. Następnie możemy uruchomić funkcję Q, aby przekształcić to w dowolny sposób, i wydrukować wynik za pomocąS .

Galaretka

Tym razem nie mogę użyć węgla drzewnego, ponieważ sprawdzający poprawność interpretera niedociążenia ulega awarii na końcu programu, jeśli program kończy się na nowej linii. (Niektóre interpretery niedociążenia, takie jak ten na TIO, nie egzekwują tej reguły, ale chciałem być odpowiednio przenośny.) Niestety, węgiel drzewny w naturalny sposób dodaje końcowe znaki nowej linii. Zamiast tego użyłem galaretki, która jest tak samo zwięzła w takich prostych przypadkach; program składa się z literału listy z dwoma elementami ( ““”) i łączy je na input ( j), interpolując w ten sposób dane wejściowe użytkownika do programu.

Przykład

Za pomocą danych wejściowych :S^(wydrukuj kopię, a następnie oceń oryginał) otrzymujemy następujący program niedociążenia:

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

Wypróbuj online!

Drukuje się nieskończenie wiele razy, w dość interesujący sposób: po wykonaniu normalnego zachowania quine, następnie uruchamia się evalna kopii tego, co wyświetla. To powoduje, że cały zrekonstruowany program uruchamia się ponownie w nieskończoność (niedociążenie jest rekurencyjne). Quiting się i robienie evaljest tak naprawdę jedynym sposobem na wykonanie nieskończonej pętli w Underload.


Węgiel drzewny nie dodaje już nowych linii (tak)
tylko ASCII

1

RProgN 2 , 11 bajtów

'{`{.%s}{'F

Objaśnienie programu

'{`{.%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>}{

Quine Explination

Wygenerowana Quine jest prosta, ale wykorzystuje funkcjonalność niedopasowanych programów obsługi funkcji w RProgN2 do stworzenia krótkiej i słodkiej quine, zwanej quine „Looping”. Jest to zaskakująco podobna koncepcja do 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.

Oczywiście, ze względu na strukturę tego quine, po funkcji konkatenate można umieścić wszystko oprócz prawdziwych operacji no-ops (których nie można powiązać), i

Niektóre kołki

  • {`{.i}{: Wyjścia {}i.{`{. ijest tylko funkcją „odwrotną”, więc ten program sam się odwraca.
  • {`{.S§.}{: Wyjścia ..S`{{{}§. Skonwertuje ciąg znaków na stos znaków, §sortuje stos leksykograficznie, a następnie .łączy go z powrotem, sam sortując .

Wypróbuj online!

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.