Генерализованный генератор Quine


19

Соревнование

В этом задании вы указываете исходный язык S и целевой язык T . Ваша задача - написать следующую программу Pна языке S. Если в качестве входных данных указана допустимая программа Qна языке , она выведет допустимую программу на языке, которая не требует ввода и вывода , то есть программу, примененную к исходному коду . Кроме того , вы должны представить в своем ответе нетривиальный пример программы (чем интереснее, тем лучше, хотя вы не набрали ни одного балла за это), итоговую программу и результаты . Это код-гольф, поэтому самый короткий код для побед.TPRTQ(R)QRQRRP

Другими словами, это проблема написания «универсального конструктора квин», который может создавать произвольные типы обобщенных квин.

Разъяснения

  • Ваш исходный и целевой языки могут быть идентичны.
  • Программа Pдолжна принимать одну строку в качестве входных данных (из STDIN или эквивалентных) и выводить одну строку (в STDOUT или эквивалентные), как и каждая выходная программаR .
  • Программы ввода Qтакже должны преобразовывать строку в другую строку, но их форма более гибкая: они могут быть функциями строка-строка, фрагментами кода, которые изменяют переменную с определенным именем, фрагментами, которые изменяют стек данных, если ваш целевой язык есть еще, и т. д. Вы также можете дополнительно ограничить форму Q, указав, например, что они могут не содержать никаких комментариев. Однако вы должны иметь возможность реализовать любую вычислимую функцию строка-строка в качестве входной программы Q, и вы должны явно указать, как они функционируют и какие дополнительные ограничения вы на них накладываете.
  • Программа вывода Rдействительно должна быть (обобщенной) формулой, поэтому она не должна читать какие-либо входные данные (пользовательский ввод, файлы и т. Д.), Если Qэто не происходит.
  • Стандартные лазейки запрещены.

Пример

Предположим, я выбрал Python в качестве исходного языка, а Haskell в качестве целевого языка, и я также требую, чтобы программа ввода представляла собой однострочное определение String -> Stringфункции с именем f. Если я дам программу перестановки строк

f x = reverse x

в качестве входных данных для моей программы на Python Pон выведет исходный код другой программы на Haskell R. Эта программа печатает на STDOUT исходный код R, но в обратном порядке. Если Pзадана функция тождества

f x = x

в качестве входных данных программа вывода Rпредставляет собой квинну.

Ответы:


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 является

{`"_~"}_~

Это работает следующим образом:

  • Нажмите на блок {`"_~"}.
  • Дублируйте это с _.
  • Выполните копию с ~.
  • Теперь внутри блока, ` превращает первый блок в его строковое представление.
  • "_~" толкает два символа источника, которые не являются частью блока (и, следовательно, отсутствуют в строковом представлении).
  • Две строки печатаются вплотную в конце программы.

В основной квине нет `необходимости, потому что если вы просто оставляете блок как есть, он все равно печатается в конце программы.

Вывод моей программы P- модифицированная версия этого фрагмента. Во-первых, я добавил +к блоку, который объединяет две строки в одну строку, содержащую весь источник. Обратите внимание, что это будет верно независимо от того, что я делаю внутри блока, потому что все это будет добавлено к строковому представлению, полученному с помощью `. Теперь я могу просто поместить программу / фрагмент 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.";

Четыре строки печатаются автоматически (вплотную) в конце программы.


1
Ну, это было быстро! И, конечно, трудно победить. Объяснение тоже приятно.
Згарб

Где вы узнали, что W% меняет направление? dl.dropboxusercontent.com/u/15495351/cjam.pdf не имеет его
Фараз Масрур

Есть ли более полный список методов?
Фараз Масрур

@FarazMasroor sourceforge.net/p/cjam/wiki/Basic%20operators/#percent (№ 3) ... это функция, заимствованная из GolfScript, и в какой-то момент кто-то сказал мне, что это работает в GolfScript. Кажется, это такая распространенная идиома, что у каждого пользователя CJam / GS есть какие-то странные неявные знания, которые на самом деле не объясняются во многих местах. (Дополнительные, не полностью документированные операторы см. На sourceforge.net/p/cjam/wiki/Operators )
Мартин Эндер,

3

Выражения на Haskell → Выражения на Haskell, 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или лямбда - выражении.
Орджан Йохансен

@ ØrjanJohansen Правильно, но я мог бы определить языковое подмножество, которое запрещает лямбду без скобок / let/ if/ case/, doесли я сам их не испускаю. Возможно, это так же хорошо, что мне не пришлось.
Андерс Касеорг

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()это JavaScript Quine . Само собой разумеется, Q(R)будет то же самое, так как Q является функцией Identity.


Некоторые заметки:

STDIN в JavaScript традиционно prompt(), однако я позволил себе воздержаться от традиции alert()STDOUT, чтобы упростить процесс запуска вывода в виде программы с использованием копирования и вставки. (Я понимаю, что могу сохранить до 12 символов при переходе наalert() ).

Я также могу сделать вещи намного короче в ES6, но сейчас я хочу остаться с Native JavaScript. Я рассматриваю возможность представить ответ S = Scala, T = ECMA6 в будущем, просто для опыта.

Я также понимаю, что JavaScript почти никогда не может победить CJam в , но мне пришлось принять этот вызов! Это было очень весело.


Благодарность! Было бы здорово иметь запись с разными исходными и целевыми языками.
Згарб

2

Желе7 , 9 байт

“ṚƓ^ṾṂ’³3

Попробуйте онлайн!

Q является функцией 7 (то есть она не выходит за пределы верхнего элемента стека и выполняет ввод / вывод через стек) и задается в качестве аргумента командной строки.

объяснение

7 программа

Универсальный конструктор quine в 7, который я использую здесь:

717162234430…3

Первое, на что следует обратить внимание, это то, что первые 7 являются эквивалентом начальных пробелов и не влияют на программу. Единственная причина, по которой это происходит, - подчиняться правилам 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для двух целей (выходной формат и начальный пробел). Очевидно, что, вставляя что-то непосредственно перед финалом 3, мы можем вывести функцию 7+ вход, а не просто выводить 7и ввод напрямую.

Как этот элемент стека попадает в собственный исходный код? Что ж, когда достигнут конец программы, evalпо умолчанию используется верхний элемент стека. Однако в процессе он фактически не извлекается из стека, поэтому приведенный литерал элемента стека evalвсе еще там. (Другими словами, программа не читает свой собственный источник - о чем свидетельствует тот факт, что она не может видеть 7в начале программы, который является разделителем элементов стека, а не частью литерала, - скорее состоит в основном из литерала, который evalприводится по умолчанию.)

Желейная программа

Это, пожалуй, одна из наименее похожих на желе программ, которые я написал; она состоит из трех nilads ( “ṚƓ^ṾṂ’, ³, 3), которые просто выводятся в последовательности , потому что никакие операции не выполняются на них. Это 3достаточно очевидно, просто являясь целочисленной константой. Это ³также просто, если вы знаете Jelly: это явное обозначение Jelly для первого аргумента командной строки (где Jelly обычно принимает свои данные). Остальная часть программы Jelly представляет основную часть моего 7 универсального конструктора quine: используя тот факт, что все команды в 7 могут быть представлены с помощью цифр ASCII, мы можем интерпретировать717162234430не как последовательность команд или даже как восьмеричное число (как это концептуально есть), а как десятичное число, означающее, что нам не нужно никакого специального форматирования для вывода. Это десятичное число становится “ṚƓ^ṾṂ’в сжатой целочисленной записи Желе.

пример

Если мы дадим в 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должны быть фрагментом кода, который изменяет единственную строку в стеке. Qчитается со стандартного ввода.

пример

Входные данные:

S*W%

Он добавляет пробел между каждыми двумя символами и переворачивает строку.

Выход:

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

Вывод обобщенной формулы:

~ _ } % 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.

Сначала он вычисляет квин, поэтому мы можем получить его строковое представление без лишних двойных кавычек. Затем замените полезную нагрузку вводом.

Это может быть место, {`"_~"+ }_~7qtгде место является заполнителем полезной нагрузки. Но изменение полезной нагрузки 7экономит байт.


1

Древесный угольPerl (5), 29 33 байта

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

Попробуйте онлайн!

Программа Perl Q должна возвращать фрагмент кода, который принимает ввод в виде строки с правой стороны и обеспечивает вывод в переменной $_. (Произвольные функции Perl могут быть преобразованы в эту форму путем переноса их как sub x {…}; $_=x. В большинстве случаев, однако, синтаксис Perl означает, что перенос не требуется.)

объяснение

Perl

Вот как выглядит универсальный Perl-конструктор Perine:

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

(В большинстве случаев вам захочется сыграть в эту игру $_=q(say…"\$_=q($_);eval");eval, но я не уверен, что вы можете вставить туда произвольный код Perl .)

Другими словами, у нас есть внешняя оболочка, $_=q(…);evalкоторая присваивает строку $_и затем оценивает ее. Внутри оболочки находится "\$_=q($_);eval", т. Е. Реконструкция оболочки вместе с ее содержимым с использованием значения, которое мы сохранили $_, плюс код Q, заданный пользователем, плюс printдля печати вывода. (К сожалению, мы не можем использовать say; он добавляет новую строку, и это актуально в кавычках.)

Древесный уголь

«Целью» этого ответа было создание обобщенных квин на Perl, поэтому, как только я разработал стратегию игры в гольф (такую ​​я использовал во многих других ответах), пришло время написать программу P, которая в основном просто заменяет строка в шаблон. Здесь мне нужен был язык, который был хорош для печати константных строк (в идеале, для их небольшого сжатия) и интерполяции пользовательского ввода в них.

Попробовав несколько, я остановился на древесном угле, который никогда раньше не использовал (и который действительно мог бы работать с некоторой документацией); Он разработан для ASCII-графики, но способен записывать строки и в одном измерении. Символы ASCII печатаются буквально в Charcoal, что означает, что для печати константных строк не требуется шаблон, и мы можем использовать команду для интерполяции строки, взятой из пользовательского ввода в программу.

Можно пойти (немного) короче, хотя. Универсальный Quine-конструктор Perl содержит два довольно длинных повторяющихся раздела. Таким образом, мы можем использовать команду, чтобы назначить их переменным (например, A…αприсваивать переменной α), и просто интерполировать переменные в строку, которую мы печатаем, используя их имена. Это экономит несколько байтов при буквальном написании строки.

К сожалению, Charcoal также добавляет новую строку в программу, но это не так уж важно; просто \nдобавить два байта для добавления этой новой строки к входу Q тоже.

пример

Если мы дадим ввод $_=reverse(который переворачивает строку), мы получим следующий вывод:

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

Попробуйте онлайн!

который похож на quine, который печатает свой источник назад, как и ожидалось.


1

ЖелеНедогруз , 15 байт

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

Попробуйте онлайн!

Принимает входную функцию недогрузки Q как командный аргумент. Q должен взять входные данные из стека и передать их в стек, не пытаясь проверить более глубокие элементы стека (так как их не будет).

объяснение

Недогрузка

Используемый здесь универсальный quine-конструктор Underload:

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

Большая часть программы является одним литералом. Мы следуем за тем :^, кто его копирует, затем оценивает одну копию (оставляя другую копию в стеке).

Когда литерал начинает вычисляться, мы запускаем a(escape, который возвращает его в ту же форму, что и исходная программа A), и (:^)*(который добавляет :^), таким образом восстанавливая исходный код всей программы. Затем мы можем запустить функцию Q, чтобы преобразовать ее произвольным образом, и вывести результат с помощью S.

Желе

На этот раз я не могу использовать Charcoal, потому что валидный интерпретатор Underload завершается с ошибкой в ​​конце программы, если программа заканчивается переводом строки. (Некоторые интерпретаторы Underload, такие как TIO, не применяют это правило, но я хотел быть правильно переносимым.) К сожалению, Charcoal, естественно, добавляет завершающие символы новой строки в свой вывод. Вместо этого я использовал Jelly, что почти так же кратко в простых случаях, подобных этому; Программа состоит из литерала списка с двумя элементами ( ““”) и объединяет их в input ( j), тем самым интерполируя пользовательский ввод в программу.

пример

Используя ввод :S^(распечатайте копию, затем оцените оригинал), мы получим следующую программу Underload:

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

Попробуйте онлайн!

Это печатает себя бесконечно много раз, довольно интересным способом: после выполнения нормального поведения quine, это тогда бежит 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>}{

Объяснение Куайна

Создаваемая квинна проста, но использует функциональность непревзойденных обработчиков функций в RProgN2 для создания короткой и приятной квинезы, называемой «циклической» квиной. Это удивительно похожая концепция на <> <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, после функции concatenate можно поместить что угодно, кроме истинных no-ops (которые не преобразуются в строку), и

Некоторые квины

  • {`{.i}{: Выходы {}i.{`{ . iэто просто «обратная» функция, поэтому эта программа выводит себя в обратном порядке.
  • {`{.S§.}{: Выходы ..S`{{{}§. Sпреобразует строку в стек символов,§ сортирует стек лексографически, затем .соединяет его обратно, выводя сам отсортированный.

Попробуйте онлайн!

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.