Узагальнений генератор квінтів


19

Змагання

У цих проблемах, ви задаєте вихідний мову S і мову перекладу T . Ваше завдання - написати наступну програму Pмовою S. Якщо дійсна програма Qна мові Tзадана як вхід P, вона виведе дійсну програму Rмовою, Tяка не приймає вводу та виведення Q(R), тобто програму, Qзастосовану до вихідного коду R. Крім того , ви маєте представити у своїй відповіді нетривіальну прикладну програму Q(чим цікавіше, тим краще, хоча ви не набрали за це балів), отриману програму Rта вихід R. Це код-гольф, тому найкоротший код для Pвиграшу.

Іншими словами, це виклик щодо написання "універсального конструктора квінок", який може створювати довільні типи узагальнених лайків.

Роз'яснення

  • Ваш вихідний та цільовий мови можуть бути однаковими.
  • Програма Pповинна приймати один рядок як вхідний (від STDIN або еквівалентний), а один рядок (STDOUT або еквівалентний), як і кожну програму виводу R.
  • Програми введення Qтакож повинні перетворювати рядок в інший рядок, але їх форма є більш гнучкою: вони можуть бути функціями "рядок-рядок", фрагментами коду, що змінюють змінну з певним іменем, фрагменти, що змінюють стек даних, якщо ваша цільова мова Ви можете також обмежити форму Q's, заявивши, що, наприклад, вони можуть не містити коментарів. Однак ви повинні мати можливість реалізовувати будь-яку обчислювану функцію "рядок-рядок" як програму введення 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

    {`"_~"+}_~
    

    Яка стандартна квітка, з додатковою +.

  2. Щоб змінити рядок у CJam, ви можете використовувати W%, так що, додавши це на STDIN, це дає:

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

    яку ми можемо запустити для отримання

    ~_}%W+"~_"`{
    
  3. В якості третьої прикладу, скажімо , ми використовуємо фрагмент , який вкраплює рядок з пробілами: ' *. Запускаючи Pце як вхід, ми отримуємо

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

    який у свою чергу друкує

    { ` " _ ~ " + '   * } _ ~  
    
  4. Тепер він також працює, якщо Qмістить розриви рядків (хоча це ніколи не потрібно в CJam). Ось програма з розривом рядка, яка видаляє всі розриви рядків з рядка (необґрунтовано заплутаним способом - розділити на рядки, а потім з'єднати):

    N/
    ""
    *
    

    Це призводить до наступного R:

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

    який у свою чергу друкує

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

Пояснення

Розглянемо спочатку отриманий вихід:

Стандартний CJam 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.";

Чотири рядки друкуються автоматично (спина назад) в кінці програми.


1
Ну, це було швидко! І звичайно важко перемогти. Пояснення теж приємне.
Згарб

Де ви дізналися, що W% обертається? dl.dropboxusercontent.com/u/15495351/cjam.pdf цього не має
Faraz Masroor

Чи є більш повний перелік методів?
Фараз Массур

@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або лямбда - вираженні.
Ørjan Johansen

@ Ø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()що є JavaScript Quine . Потрібно сказати, Q(R)що те саме буде, оскільки Q - функція Identity.


Деякі примітки:

STDIN в JavaScript традиційно prompt(), однак, я дозволив собі утриматися від традиції alert()як STDOUT, щоб полегшити процес запуску виводу як програми, використовуючи copy-paste. (Я розумію, що можу зберегти до 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 (що означає «друкувати буквально, використовуючи те саме кодування, що і вихідний код», і, таким чином, явно є найкращим кодуванням для лайки). Тут досить пощастило, що ми можемо повторно використовувати літерал 7для двох цілей (вихідний формат та провідний пробіл). Ясно, що, вставивши щось безпосередньо перед фіналом 3, ми можемо вивести функцію 7+ введення, а не просто виведення 7та ввести безпосередньо.

Як цей елемент стека отримує власний вихідний код? Ну а коли буде досягнуто кінця програми, evalза замовчуванням 7 с верхній елемент стека. Однак він насправді не вискочив із стека в процесі, тому літеральний елемент стека, який evalведуть, все ще є. (Іншими словами, програма не читає власне джерело - про що свідчить той факт, що вона не в змозі побачити 7на початку програми, що є роздільником елементів стека, а не частиною буквального - але, скоріше, це здебільшого складається з літералу, який evalприводиться за замовчуванням.)

Програма желе

Це, мабуть, одна з найменш схожих на Jelly програм, про які я писав; вона складається з трьох nilads ( “ṚƓ^ṾṂ’, ³, 3), які просто виводяться в послідовності , тому що ніякі операції не виконуються на них. 3Очевидно досить, просто бути цілою константою. Це ³також просто, якщо ви знаєте Jelly: це явне позначення Jelly для першого аргументу командного рядка (саме там Jelly зазвичай бере свій внесок). Решта програми Jelly представляє основну частину мого 7 універсального конструктора quine: використовуючи той факт, що всі команди в 7 можна представити за допомогою цифр ASCII, ми можемо інтерпретувати717162234430не як серія команд, або навіть як восьмеричне число (як це концептуально), а як десятковий номер, що означає, що нам не потрібно спеціального форматування для виводу. Це десяткове число стає “ṚƓ^ṾṂ’у стислих цілих позначеннях 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 повинен бути фрагментом коду, який змінює єдиний рядок у стеку. Qчитається з stdin.

Приклад

Вхід:

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.

По-перше, це оцінює quine, тому ми можемо отримати її рядкове представлення без зайвих подвійних лапок. Потім замініть корисне навантаження на вхід.

Це може бути місце, {`"_~"+ }_~7qtде місце є заповнювачем корисного навантаження. Але зміна корисного навантаження 7економить байт.


1

Деревне вугілляPerl (5), 29 33 байт

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

Спробуйте в Інтернеті!

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

Пояснення

Перл

Ось як виглядає універсальний конструктор Quine quine:

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

(У більшості випадків ви хочете переграти це в гольф $_=q(say…"\$_=q($_);eval");eval, але я не впевнений, що ви можете помістити до нього довільний код Perl .)

Іншими словами, у нас є зовнішня обгортка, $_=q(…);evalяка присвоює рядок $_і потім оцінює її. Всередині обгортки - "\$_=q($_);eval"це реконструкція обгортки разом з її вмістом за допомогою значення, яке ми зберігаємо $_, плюс код Q, визначений користувачем, плюс printдля друку виводу. (На жаль, ми не можемо використовувати say; він додає новий рядок, і це актуально в лайнерах.)

Вугілля

«Суть» цієї відповіді полягала в тому, щоб створити узагальнені лайки в Perl, тож як тільки у мене була стратегія гольфу для цього (яку я використовував у багатьох інших відповідях), настав час написати програму P, яка в основному просто підміняє рядок у шаблон. Мені тут хотілося мови, яка добре роздруковувала постійні рядки (в ідеалі трохи їх стискаючи) та інтерполюючи введення користувачів у них.

Спробувавши кілька, я оселився на вугіллі, якого я ніколи раніше не використовував (і який справді міг би зробити з деякою документацією); він розроблений для мистецтва ASCII, але також здатний писати рядки в одному вимірі. Символи ASCII надруковані буквально на вугільному вугіллі, це означає, що для друку постійних рядків немає котла, і ми можемо використовувати команду для інтерполяції рядка, взятого з введення користувача в програму.

Можна хоч (трохи) коротше, хоча. Універсальний конструктор quine Perl містить два досить довгих повторюваних розділу. Таким чином, ми можемо використовувати команду для присвоєння їм змінних (наприклад, A…αприсвоює зміннійα ) та просто інтерполювати змінні у рядок, який ми друкуємо, використовуючи їх імена. Це економить кілька байтів на простому буквальному написанні рядка.

На жаль, Charcoal також додає нову лінію до програми, але це не величезна справа; це просто коштує два байти за а, \nщоб додати цей новий рядок також до вводу Q.

Приклад

Якщо ми дамо вхід $_=reverse(який обертає рядок), отримаємо такий вихід:

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

Спробуйте в Інтернеті!

що подібне квіні, яке друкує своє джерело назад, як і очікувалося.


1

ЖелеЗавантаження , 15 байт

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

Спробуйте в Інтернеті!

Приймає функцію Q "Underload" як аргумент, що нагадує команду. Q повинен приймати вхід зі стека і виштовхувати вихід у стек, не намагаючись перевірити більш глибокі елементи стека (оскільки вони не існуватимуть).

Пояснення

Підгрузка

Універсальний конструктор Quine, використаний тут:

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

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

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

Желе

Цього разу я не можу використовувати вугілля, оскільки в кінці програми виходить перевіряючий інтерпретатор Underload, якщо програма закінчується новим рядком. (Деякі інтерпретатори Underload, такі, як TIO, не виконують цього правила, але я хотів бути належним чином переносним.) На жаль, Charcoal природно додає у свій вихід нові рядки. Натомість я використав Jelly, який майже такий же короткий у простих випадках, як цей; програма складається з літералу списку з двома елементами ( ““”) і з'єднує їх на вході ( j), тим самим інтерполюючи вхід користувача в програму.

Приклад

Використовуючи вхід :S^(надрукуйте копію, потім оцініть оригінал), ми отримаємо таку програму Underload:

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

Спробуйте в Інтернеті!

Це друкує себе нескінченно багато разів, досить цікавим чином: після виконання нормальної поведінки у квінею він потім працює evalна копії того, що виводиться. Це змушує всю реконструйовану програму запускатися знову, нескінченно (Underload є рекурсивним хвостом). Вихід із себе та виконання evalсправді - це єдиний спосіб зробити нескінченний цикл у програмі Underload.


Деревне вугілля більше не додає останніх рядків (так)
лише 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>}{

Quine Explination

Квінка, яка виробляється, проста, але використовує функціональні можливості невідмінних обробників функцій у 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.

Звичайно, через структуру цієї квінти все, крім справжніх не-опій (які не піддаються строчці), може бути розміщено після конкатенатної функції, і

Деякі лайки

  • {`{.i}{: Виходи {}i.{`{. iє лише функцією "обернення", тому ця програма виводить себе назад.
  • {`{.S§.}{: Виходи ..S`{{{}§. Sперетворює рядок у стек символів, §сортує стек лексографічно, потім .з'єднує його назад, виводячи себе відсортованим.

Спробуйте в Інтернеті!

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.