一般化されたQuine Generator


19

チャレンジ

このチャレンジでは、ソース言語 Sターゲット言語 を指定しますT。あなたの仕事は、次のプログラムPを言語で書くことですSQ言語の有効なプログラムがのT入力として与えられた場合、入力と出力を受け取らない言語のP有効なプログラム、つまりのソースコードに適用されるプログラムを出力します。さらに、答えには自明ではないサンプルプログラム(より面白く、より良いが、これに対してポイントを獲得しませんが)、結果のプログラム、およびの出力を提示する必要があります。これはコードゴルフですので、勝つための最短のコードです。RTQ(R)QRQRRP

言い換えれば、これは、任意のタイプの一般化されたクインを作成できる「ユニバーサルクインコンストラクター」の作成に関する課題です。

明確化

  • ソース言語とターゲット言語は同一である場合があります。
  • プログラムPは、すべての出力プログラムと同様に、入力として1つのストリング(STDINまたは同等のものから)を受け取り、1つのストリング(STDOUTまたは同等のものへ)を出力する必要がありますR
  • 入力プログラムQも文字列を別の文字列に変換する必要がありますが、その形式はより柔軟です:文字列から文字列への関数、特定の名前の変数を変更するコードスニペット、ターゲット言語の場合にデータスタックを変更するスニペットなどがありQます。たとえば、コメントを含めないことを指定することで、の形式をさらに制限することもできます。ただし、任意の計算可能な文字列から文字列への関数を入力プログラムとして実装できる必要があり、それらがどのように機能し、どのような制約を課すかを明示的に指定Qする必要があります。
  • 出力プログラムRは、実際には(一般化された)クインである必要があります。Qしたがって、そうしない限り、入力(ユーザー入力、ファイルなど)を読み取ってはなりません。
  • 標準の抜け穴は許可されていません。

ソース言語としてPythonを選択し、ターゲット言語としてHaskellを選択し、さらに入力プログラムがString -> Stringという名前の関数の1行の定義であることを要求するとします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. IDは空のスニペットであるため、STDINを空のままにします

    {`"_~"+}_~
    

    これは標準のクインであり、追加の+

  2. CJamの文字列を反転するには、を使用できますW%。これをSTDIN に追加すると、次のようになります。

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

    取得するために実行できます

    ~_}%W+"~_"`{
    
  3. 3番目の例として、スペースを含む文字列を散在させるスニペットを使用するとします' *Pそれを入力として実行すると、

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

    次に印刷する

    { ` " _ ~ " + '   * } _ ~  
    
  4. Q改行が含まれている場合にも機能するようになりました(ただし、CJamでは必要ありません)。改行を含むプログラムを次に示します。このプログラムは、文字列からすべての改行を削除します(不必要に複雑な方法で-行に分割してから結合します)。

    N/
    ""
    *
    

    これにより、次の結果が得られますR

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

    次に印刷する

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

説明

最初に生成された出力を見てみましょう。

標準のCJamクインは

{`"_~"}_~

次のように機能します。

  • ブロックを押します{`"_~"}
  • で複製し_ます。
  • でコピーを実行します~
  • ブロック内で、`最初のブロックを文字列表現に変換します。
  • "_~" ブロックの一部ではない(したがって、文字列表現にない)ソースの2文字をプッシュします。
  • 2つの文字列は、プログラムの最後に連続して印刷されます。

基本的なクインで`は、これは不要です。ブロックをそのままにしておくと、プログラムの最後にすべて同じように印刷されるためです。

私のプログラムの出力は、Pこのスニペットの修正バージョンです。まず、+ブロックにを追加しました。これは、2つの文字列を連結して、ソース全体を含む1つの文字列にします。これは、ブロック内で何をしても関係ありません。これは、で取得した文字列表現にすべて追加されるため`です。ここで、プログラム/スニペット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つの文字列は、プログラムの最後に自動的に(連続して)印刷されます。


1
まあ、これは速かったです!そして確かに打ち負かすのは難しい。説明もいいです。
ズガルブ14

W%が逆転することをどこで知りましたか?dl.dropboxusercontent.com/u/15495351/cjam.pdfにはありません
ファラズマスロ

メソッドのより完全なリストはありますか?
ファラズマスロア

@FarazMasroor sourceforge.net/p/cjam/wiki/Basic%20operators/#percent(no。3)...これはGolfScriptから借用した機能で、ある時点で誰かがGolfScriptでの動作を教えてくれた。これは一般的なイディオムのようで、すべてのCJam / GSユーザーが持っている奇妙な暗黙の知識ですが、実際には多くの場所で説明されていません。(詳細については、完全に文書化されていない演算子については、sourceforge.net / p / cjam / wiki / Operatorsを参照してください)
Martin Ender

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

$括弧だけでなく、末尾のletdoまたはラムダ式も必要です。
Ørjanヨハンセン

@ØrjanJohansenそうですが、括弧なしのlambda / 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のクワイン。言うまでもなくQ(R)、Qは恒等関数なので、同じになります。


いくつかのメモ:

JavaScriptのSTDINは伝統的prompt()にですが、alert()コピーペーストを使用して出力をプログラムとして実行するプロセスを簡単にするために、STDOUT の伝統を控えることを許可しました。(に変更すると、最大12文字まで保存できることに気付きましたalert())。

ES6でもっと短くすることもできますが、今のところはネイティブJavaScriptのままにしておきます。経験のために、将来S = Scala、T = ECMA6の回答を提出することを検討しています。

また、JavaScriptがCJamに勝つことはほとんどないこともわかっていが、この挑戦​​をしなければなりませんでした!とても面白かったです。


ありがとう!異なるソース言語とターゲット言語を使用してエントリを作成することは、実にクールです。
ズガルブ14年

2

ゼリー7、9つのバイト

“ṚƓ^ṾṂ’³3

オンラインでお試しください!

Qは7関数であり(つまり、最上位のスタック要素を超えて見えず、スタックを介してI / Oを実行します)、コマンドライン引数として指定されます。

説明

7プログラム

ここで使用している7のユニバーサルクインコンストラクターは次のとおりです。

717162234430…3

最初に注意することは、先頭の7は先頭の空白と同等であり、プログラムに影響を与えないことです。それが存在する唯一の理由は、リテラルのみのクインに対するPPCGのルールに従うことです(それ1は、それ自体ではなく、プログラムの2番目によってエンコードされます)。

プログラムの残りの部分は単一のスタック要素(バランス7の取れたsと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デフォルトで主導されるリテラルで主に構成されます。)

ゼリープログラム

これはおそらく、私が書いた中で最もゼリーに似たゼリープログラムの1つです。それは3 nilads(で構成されて“ṚƓ^ṾṂ’³3何も操作がそれらに行われていないので、順番にだけ出力されます)。これ3は十分に明白で、整数定数です。これ³は、Jellyを知っていれば簡単です。最初のコマンドライン引数に対するJellyの明示的な表記法です(Jellyは通常、入力を受け取ります)。Jellyプログラムの残りの部分は、私の7つのユニバーサルクインコンストラクターの大部分を表しています。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の2つのコピーが得られます。

7171622344302405371716223443024053

2

CJam →CJam、13バイト

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

オンラインでお試しください!

入力Qは、スタック内の唯一の文字列を変更するコードスニペットである必要があります。Qstdinから読み取られます。

入力:

S*W%

2文字ごとにスペースを追加し、文字列を反転します。

出力:

{`"_~"+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クインコンストラクターは次のようになります。

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

(ほとんどの場合$_=q(say…"\$_=q($_);eval");eval、これをにしたいでしょうが、任意のPerlコードをそこに収めることができるかどうかはわかりません。)

つまり、$_=q(…);eval文字列を割り当てて$_評価する外部ラッパーがあります。ラッパーの内部には"\$_=q($_);eval"、つまり、に格納した値と$_ユーザーが指定したコードQを使用printして、出力を印刷することにより、ラッパーとその内容を再構成します。(残念ながら、使用することはできませんsay;それは改行を追加し、それはクインに関連しています。)

この回答の「ポイント」は、Perlで一般化されたクインを作成することでした。そのため、ゴルフ戦略(他の多くの回答で使用した戦略)を作成したら、プログラムPを作成します。テンプレートへの文字列。ここで欲しかったのは、定数文字列の印刷(理想的にはそれらを少し圧縮する)と、それらへのユーザー入力の補間が得意な言語でした。

いくつか試してみた後、私は炭を使用することに決めました。ASCIIアート用に設計されていますが、1次元で文字列を書き込むこともできます。ASCII文字は文字通りCharcoalで印刷されます。つまり、定数文字列の印刷は定型文を使用せず、コマンドを使用してユーザー入力から取得した文字列をプログラムに挿入できます。

ただし、(わずかに)短くすることもできます。Perlユニバーサルクインコンストラクターには、2つのかなり長い繰り返しセクションが含まれています。私たちは、このように使用することができます(たとえば、変数に割り当てるためにコマンドをA…α割り当て変数にα)、そして単純に我々はしているが、自分の名前を使用して経由で印刷する文字列に変数を補間します。これにより、文字列をそのまま文字通りに書き込むだけで数バイト節約できます。

残念ながら、Charcoalはプログラムに改行も追加しますが、それは大したことではありません。\nその改行をQの入力に追加するために、単に2バイトかかるだけです。

入力$_=reverse(文字列を逆にする)を与えると、次の出力が得られます。

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

オンラインでお試しください!

これは、予想どおり、ソースを逆方向に印刷する、似たようなものです。


1

ゼリーアンダーロード、15バイト

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

オンラインでお試しください!

入力のアンダーロード関数Qをコマンドのような引数として受け取ります。Qは、より深いスタック要素(存在しないため)を検査することなく、スタックから入力を取得し、出力をスタックにプッシュする必要があります。

説明

アンダーロード

ここで使用されるアンダーロードユニバーサルクインコンストラクタは次のとおりです。

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

プログラムのほとんどは単一のリテラルです。私たちは、であること従って:^いるコピー、それは、その後、一つのコピー(スタック上の他のコピーを残す)を評価します。

リテラルの評価が開始されると、a(エスケープして元のprogramAと同じ形式に戻します)、(:^)*(追加する:^)を実行して、プログラム全体のソースコードを再構築します。その後、関数Qを実行してこれを任意の方法で変換し、結果をで出力できSます。

ゼリー

プログラムが改行で終了すると、検証アンダーロードインタープリターがプログラムの最後でクラッシュするため、今回はCharcoalを使用できません。(TIOなどの一部のアンダーロードインタープリターは、このルールを強制しませんが、適切に移植できるようにしたかったのです。)残念ながら、Charcoalは当然、出力に末尾の改行を追加します。代わりに、私はゼリーを使用しました。これは、このような単純なケースではほとんど簡潔です。プログラムは、2つの要素(““”)を持つリストリテラルで構成され、それらを入力(j)で結合します。したがって、ユーザー入力をプログラムに挿入します。

入力を使用して:S^(コピーを印刷してから元を評価する)、次のアンダーロードプログラムを取得します。

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

オンラインでお試しください!

これは、かなり興味深い方法で無限に何度も印刷されます。通常のクインの動作を実行evalした後、出力内容のコピーで実行されます。これにより、再構築されたプログラム全体が無期限に再実行されます(Underloadは末尾再帰です)。Underloadでeval無限ループを実行する唯一の方法は、実際に自分自身をやめて実行することです。


木炭は末尾の改行をもう追加しません(はい)
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の比類のない関数ハンドラーの機能を使用して、「ルーピング」クインと呼ばれる短くて甘いクインを作成します。これは、<> <クインに驚くほど似た概念です。

{`{.}{
{`{.}   # 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文字列を文字のスタックに変換し§、スタックを辞書順にソートしてから、.結合して戻し、ソートされた状態で出力します。

オンラインでお試しください!

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.