广义奎因发生器


19

挑战

在此挑战中,您将指定源语言 S目标语言 T。您的任务是P用该语言编写以下程序S。如果输入了有效Q语言的程序T作为输入P,它将以有效R语言T输出没有输入和输出的有效程序Q(R),即Q应用于的源代码的程序R此外,您应该在答案中提供一个简单的示例程序Q(越有趣,越好,尽管您对此没有得分),结果程序R以及的输出R。这是代码高尔夫球,因此是P获胜的最短代码。

换句话说,这对于编写一个可以创建任意类型的广义quines的“通用quine构造函数”是一个挑战。

澄清说明

  • 您的源语言和目标语言可能相同。
  • 程序P应采用一个字符串作为输入(来自STDIN或等效的字符串),并输出一个字符串(至STDOUT或等效字符串),每个输出程序也应如此R
  • 输入程序Q还应该将一个字符串转换为另一个字符串,但是它们的形式更加灵活:它们可以是字符串到字符串的函数,可以使用特定名称修改变量的代码段,可以使用目标语言来修改数据堆栈的代码段有一个,等等。您还可以Q通过声明例如可能不包含任何注释来进一步限制的形式。但是,您必须能够将任何可计算的字符串到字符串函数实现为输入程序Q,并且必须明确说明它们的功能以及对它们施加的进一步约束。
  • 输出程序R实际上应该是一个(通用的)quine,所以除非Q这样做,否则它不得读取任何输入(用户输入,文件等)。
  • 不允许出现标准漏洞

一个例子

假设我选择Python作为源语言,选择Haskell作为目标语言,并且进一步要求输入程序应该是String -> String名为的函数的单行定义f。如果我提供反向字符串程序

f x = reverse x

作为我的Python程序的输入P,它将输出另一个Haskell程序的源代码R。该程序将的源代码打印到STDOUT R,但相反。如果P赋予身份功能

f x = x

作为输入,输出程序R是一个quine。

Answers:


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
好吧,这太快了!当然很难被击败。解释也很好。
Zgarb 2014年

您从哪里得知W%会逆转?dl.dropboxusercontent.com/u/15495351/cjam.pdf没有它
法拉兹Masroor

有更完整的方法列表吗?
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

不只是$需要括号,也尾随letdo或lambda表达式。
与Orjan约翰森

@Ø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函数。


一些注意事项:

JavaScript中的STDIN是传统的prompt(),但是,我允许自己避免使用alert()as STDOUT 的传统,以使使用复制粘贴将输出作为程序运行的过程更加容易。(我确实意识到,更改为时,我最多可以保存12个字符alert())。

我还可以在ES6中简化一些事情,但现在我想保留使用Native JavaScript。我正考虑出于经验考虑,将来提交S = Scala,T = ECMA6答案。

我还意识到JavaScript几乎不可能在击败CJam,但是我不得不接受这一挑战!非常有趣。


谢谢!具有不同源语言和目标语言的条目确实很酷。
Zgarb 2014年

2

果冻7,9字节

“ṚƓ^ṾṂ’³3

在线尝试!

Q是7函数(即,它看起来不超出顶部堆栈元素,并且通过堆栈进行I / O),并作为命令行参数给出。

说明

7程序

我在这里使用的7中的通用quine构造函数是:

717162234430…3

首先要注意的是,前导7等同于前导空格,并且对程序没有任何影响。它存在的唯一原因是要遵守PPCG的针对纯字面量的quins规则(它是由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用于两个目的(输出格式和前导空白)。显然,通过在final之前插入一些内容3,我们可以输出7+输入的函数,而不仅仅是输出7和直接输入。

这个堆栈元素如何获得自己的源代码?好了,当到达程序末尾时eval,默认情况下,顶部堆栈元素为7 s。但是,它实际上并没有从进程中弹出,因此导致的栈元素文字eval仍然存在。(换句话说,该程序不是在读取自己的源代码-事实是它无法7在程序开始时看到,这是一个堆栈元素分隔符,而不是文字的一部分-而是主要eval由默认情况下首字母开头的文字组成。)

果冻计划

这也许是我编写的最少的类似于Jelly的Jelly程序之一。它包括三个nilads( ,“ṚƓ^ṾṂ’³),3因为没有操作对它们执行在序列上只输出。将3是显而易见的是,只是作为一个整型常量。的³,如果你知道果冻也很简单:它是果冻的第一个命令行参数明确的符号(这是果冻一般需要它的输入)。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%}_~

广义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函数包装为可以将任意Perl函数转换为这种形式sub x {…}; $_=x。不过,在大多数情况下,Perl的语法意味着不需要包装。)

说明

Perl

通用Perl quine构造函数如下所示:

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

(在大多数情况下,您希望将其降低到$_=q(say…"\$_=q($_);eval");eval,但是我不确定您是否可以在其中放入任意Perl代码。)

换句话说,我们有一个外部包装器$_=q(…);eval,它将一个字符串分配给$_它,然后对其求值。包装器内部是"\$_=q($_);eval",即通过使用我们存储在中的值对包装器及其内容进行的重构$_,再加上用户指定的代码Q,再加print上打印输出。(不幸的是我们不能使用say;它增加了一个换行符,这与奎因有关。)

木炭

这个答案的“重点”是在Perl中生成广义的quines,所以一旦我有了一个可行的策略(我在许多其他答案中都使用过),就该编写程序P了,基本上可以替代它字符串插入模板。我在这里想要的是一种擅长打印常量字符串(理想情况下将它们压缩一点)并将用户输入插值到其中的语言。

尝试了几次之后,我选择了以前从未使用过的Charcoal(它确实可以处理一些文档)。它是为ASCII艺术设计的,但也能够在一维中写入字符串。ASCII字符实际上是用木炭打印的,这意味着打印常量字符串不需要任何样板,并且我们可以使用该命令将用户输入的字符串插入到程序中。

不过,可能会(略)短一些。Perl通用quine构造函数包含两个相当长的重复部分。因此,我们可以使用命令将它们分配给变量(例如,A…α分配给变量α),然后通过使用变量名将变量内插到我们正在打印的字符串中。与仅按字面意义写入字符串相比,这节省了几个字节。

不幸的是,木炭还向该程序添加了换行符,但这并不是什么大问题。只需花费两个字节\n即可将换行符也添加到Q的输入中。

如果提供输入$_=reverse(反转字符串),则会得到以下输出:

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

在线尝试!

这是一个类似quine的字符串,按预期方式向后打印源。


1

果冻欠载,15字节

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

在线尝试!

将输入的Underload函数Q作为类似命令的参数。Q必须从堆栈中获取输入并将输出推入堆栈,而无需尝试检查更深的堆栈元素(因为它们将不存在)。

说明

欠载

这里使用的Underload通用quine构造函数是:

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

大部分程序是单个文字。我们紧随:^其后的是,它将进行复制,然后评估一个副本(将另一个副本留在堆栈中)。

当文字开始求值时,我们运行a(转义,将其恢复为与原始programA相同的形式),然后运行(:^)*(附加:^),从而重建了整个程序的源代码。然后,我们可以运行函数Q以任意方式对其进行转换,并使用打印结果S

果冻

这次我无法使用Charcoal,因为如果程序以换行符结尾,则验证的Underload解释程序将在程序末尾崩溃。(一些Underload解释器,例如TIO上的解释器,不执行此规则,但我想适当地移植。)不幸的是,木炭自然在其输出中添加了尾随换行符。相反,我使用了Jelly,它在像这样的简单情况下几乎很简洁;该程序由具有两个元素(““”)的列表文字组成,并将它们连接到input(j)上,从而将用户输入插值到程序中。

使用输入:S^(打印副本,然后评估原件),我们得到以下欠载程序:

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

在线尝试!

这会以一种非常有趣的方式无数次地打印自身:在执行了正常的quine行为之后,然后eval在输出内容的副本上运行。这将导致整个重建的程序无限期地再次运行(负载为尾递归)。弄混自己并做一个eval实际上是在欠载中执行无限循环的唯一方法。


木炭不再添加尾随换行符(是)
ASCII码,仅ASCII,2007年

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很简单,但是使用了RProgN2中无与伦比的函数处理程序的功能来创建简短而甜美的quine,称为“ Looping” 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(不会被字符串化)之外的任何东西都可以放在连接函数之后,并且

一些奎因

  • {`{.i}{:输出{}i.{`{i只是“反向”功能,因此该程序将自身输出为反向。
  • {`{.S§.}{:输出..S`{{{}§S将字符串转换为字符堆栈,§按字母顺序对堆栈进行排序,然后.将其重新连接在一起,输出排序后的自身。

在线尝试!

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.