您的任务很简单:编写一个无需输入即可输出(或返回)其源代码的程序(或函数)。要注意的是,当将程序包装为"quotes"
(Unicode字符34)时,它应该再次输出其(现在已引用)源代码。
奎因的标准规则适用。这是代码高尔夫球,因此最短的程序(以字节为单位)获胜。
!
...的实现
"
吗?某些语言支持两个或三个引号字符。
您的任务很简单:编写一个无需输入即可输出(或返回)其源代码的程序(或函数)。要注意的是,当将程序包装为"quotes"
(Unicode字符34)时,它应该再次输出其(现在已引用)源代码。
奎因的标准规则适用。这是代码高尔夫球,因此最短的程序(以字节为单位)获胜。
!
...的实现
"
吗?某些语言支持两个或三个引号字符。
Answers:
这个版本的工作方式与其他版本相同,只是我忘了Noodel可以运行一次代码块,而我却做了这种语言...
Ḷ1ḥ-Ð1ḥ@€
ḷḥ-Ðḥ@ḅ
ḷḥ-Ðḥ@ḅ # Single statement that builds itself as a string.
ḷ # Loop the following block of code unconditionally.
ḥ- # Push the string literal of the token preceding this one which pushes "ḷ" onto the stack.
Ð # Push the stack as an array to stdout (since is an array it is done by reference).
ḥ@ # Push the string literal for this block of code which pushes "ḥ-Ðḥ@ḅ" onto the stack.
ḅ # Break out of the given loop. (The stack is now ["ḷ", "ḥ-Ðḥ@ḅ"]).
# The top of the stack is popped off and displayed which modifies the array to produce {["ḷ"], "ḥ-Ðḥ@ḅ"} in stdout.
"
因为Noodel有一组专用于我所说的可打印字符的字符,所以可以在程序之前和之后放置字符。当它们自己放置时,它们立即被解析为字符串文字,并允许轻松地将某些内容打印到屏幕上。因此,与大多数语言不同,Noodel认为普通的ASCII集被视为值得打印的直接字符串文字(空格和换行符除外),其中引用该代码仅被视为推入字符串。
"ḷḥ-Ðḥ@ḅ"
" # Pushes on the string literal "\"" onto the stack.
ḷḥ-Ðḥ@ḅ # Same execution as before, simply builds the Quine for this loop.
ḷ # Loop the following block of code unconditionally.
ḥ- # Push the string literal of the token preceding this one which pushes "ḷ" onto the stack.
Ð # Push the stack as an array to stdout (since is an array it is done by reference).
ḥ@ # Push the string literal for this block of code which pushes "ḥ-Ðḥ@ḅ" onto the stack.
ḅ # Break out of the given loop. (The stack is now ["\"", "ḷ", "ḥ-Ðḥ@ḅ"]).
" # Pushes on the string literal "\"" onto the stack.
# The top of the stack is popped off and displayed which modifies the array to produce {["\"", "ḷ", "ḥ-Ðḥ@ḅ"], "\""} in stdout.
<div id="noodel" code='ḷḥ-Ðḥ@ḅ' input="" cols="10" rows="1"></div>
<script src="https://tkellehe.github.io/noodel/noodel-latest.js"></script>
<script src="https://tkellehe.github.io/noodel/ppcg.min.js"></script>
<div id="noodel" code='"ḷḥ-Ðḥ@ḅ"' input="" cols="10" rows="1"></div>
<script src="https://tkellehe.github.io/noodel/noodel-latest.js"></script>
<script src="https://tkellehe.github.io/noodel/ppcg.min.js"></script>
e
无效。该问题并不要求输入编码为字节34的字符,而是要求输入Unicode字符34。无论使用哪种编码,都只有一个:"
"
?(对不起,只是想确保我理解您的意思)。此外,我是否应该删除答案中所有有关using的文字e
?
"
可行,我将删除讨论并仅使用"
。
""" """>" "or exec("oct=0");p='"""" """>" "or exec("oct=0");p=%r;a=oct==0;print(p[a:~a]%%p)#".';a=oct==0;print(p[a:~a]%p)#
在线尝试!TIO带有一个页眉和页脚,它们可以自动测试卷装的有效性。您可以清除它们以运行quine。
该代码通过在Python中使用三引号字符串来工作。""" """
等于' '
并"""" """
等于'" '
。
该代码确实使用exec
,但不是用于将数据作为代码执行的“非快速”方式,仅用于从表达式内部设置变量。在exec
被正确编码的数据了。
第一条语句将字符串(可能带有引号)与进行比较" "
,并相应地设置变量oct
。(该变量可能是任何简短的内置变量。)
然后,其余代码使用%r
字符串格式实现传统的Python quine ,并带有一些其他代码,如果oct
未更改,这些代码将去除多余的引号。
使用“ cheaty”的替代版本exec
以126个字节出现,重复代码较少:
""" """>" "and exec("oct=0");s='"""" """>" "and exec("oct=0");s=%r;p=%r;exec(p)#".';p='a=oct!=0;print(s[a:~a]%(s,p))';exec(p)#
";str(chr 34)^it;(print(it^it);fn x=>print(x^it^x^it))";str(chr 34)^it;(print(it^it);fn x=>print(x^it^x^it))
未报价的版本:在codingground上尝试。
引用的版本:在codingground上尝试。
请注意,输出看起来像这样
> val it = "{some string}" : string
> val it = "{some string}" : string
{output to stdout}> val it = fn : string -> unit
因为代码是按声明进行解释的声明(每个声明都;
结束一个声明),并显示每个声明的值和类型。
在SML中,有一个形式的quine <code>"<code in quotes>"
:
str(chr 34);(fn x=>print(x^it^x^it))"str(chr 34);(fn x=>print(x^it^x^it))"
另一种形式"<code in quotes>"<code>
:
";str(chr 34)^it;print(it^it)";str(chr 34)^it;print(it^it)
两者都依赖于<code>
-part不包含引号的事实,因此可以引号而无需转义任何内容,"
输出quine 的需要由给出str(chr 34)
。
它们还严重依赖于隐式标识符it
,该隐式标识符在声明中未给出显式标识符时使用。
在第一个quine中str(chr 34);
绑定it
到包含的字符串"
,fn x=>
启动一个带一个参数的匿名函数x
,然后连接x^it^x^it
并打印结果字符串。此匿名函数直接应用于包含程序代码的字符串,因此串联x^it^x^it
产生<code>"<code>"
。
第二个quine仅以";str(chr 34)^it;print(it^it)";
绑定到的程序代码作为字符串开始it
。然后str(chr 34)^it;
将引号连接到字符串的开头,并且再次没有给出明确的标识符,结果字符串"<code>
绑定到it
。最后,print(it^it)
将字符串与其本身的yield连接起来"<code>"<code>
,然后将其打印出来。
编辑:不再是最新的108字节版本,但是在阅读了此说明之后,人们也可能会理解它。
引号安全的quine结合了上述两种方法,并且本身就是形式"<code>"<code>
。将其再次放在引号中会产生""<code>"<code>"
,因此我们得到一个空字符串,然后是另一种形式的奎因。
这意味着该程序要么"<code>
以标识符的形式为其提供了自己的源it
,要么it
是公正的"
,并且给了我们自己的源<code>
作为参数,因此必须是处理此类参数的函数。
(if size it>1then(print(it^it);fn _=>())else fn x=>print(it^it^x^it^x^it))
为了确定在哪种情况下,我们检查的大小it
是否大于1。如果不是,it
则为is "
,并且在第二种情况下,因此else
-part返回一个匿名函数fn x=>print(it^it^x^it^x^it)
,该函数随后被调用,因为其后跟源为字符串。请注意it^it^
程序开头的空字符串所需的前导。
如果size it
大于1,那么我们在then
-part中执行print(it^it)
,对吧?不完全是,因为我忘了告诉你,SML是强类型的,这意味着一个条件if <cond> then <exp_1> else <exp_2>
必须始终具有相同类型的这又意味着该表达式<exp_1>
,并<exp_2>
需要有相同的类型。我们已经知道了该else
部分的类型:一个匿名函数,该函数接受一个字符串然后调用,该函数print
具有type string -> <return type of print>
,并且print
具有type string -> unit
(unit
在某种程度上类似于void
其他语言),因此生成的type也是string -> unit
。
因此,如果then
零件只是print(it^it)
具有type 的部分unit
,我们将收到类型不匹配错误。那又如何fn _=>print(it^it)
呢?(_
是未使用的参数的通配符)此匿名函数本身具有类型'a -> unit
,其中,'a
代表任意类型,因此在我们的条件(该条件强制执行一个string -> unit
类型)的情况下,它将起作用。(type变量'a
使用type实例化string
。)但是,在这种情况下我们将不会打印任何内容,因为永远不会调用匿名函数!记住,当我们进入then
-part时,整体代码为"<code>"<code>
,因此<code>
-part的值等于一个函数,但由于后面没有任何内容,因此不会调用它。
相反,我们使用具有形式sequentialisation (<exp_1>; ...; <exp_n>)
其中<exp_1>
以<exp_n-1>
可有任意类型和类型<exp_n>
提供了全sequentialisation的类型。从功能的角度来看,<exp_1>
to 的值<exp_n-1>
被简单地丢弃,但是SML还支持命令式构造,因此表达式可能会有副作用。简而言之,我们将其(print(it^it);print)
作为then
-part,因此首先打印,然后返回print
具有正确类型的函数。
éPñi"éP241"qpá"lxx|xÿ
由于其中包含一些无法打印的字符,因此以下是可读版本:
éPñi"éP<C-v>241<esc>"qpá"lxx|xÿ
这是一个十六进制转储:
00000000: e950 f169 22e9 5016 3234 311b 2271 70e1 .P.i".P.241."qp.
00000010: 226c 7878 7c78 ff "lxx|x.
因此,我们要做的第一件事就是确定第一个字符是否为引号。éP
插入一个“ P”字符,但"éP
为NOOP。在那之后,我们对标准可扩展quine进行了少许修改,即:
ñi<C-v>241<esc>"qpÿ
不过,我们将略有不同。首先,我们需要插入起始的“éP”文本。所以我们做
ñ " Start recording into register 'q'
i " Enter insert mode
"éP<C-v>241<esc> " Enter the following text: '"éPñ'
"qp " Paste the text in register 'q'
á" " Append a '"'
这是分支发生的地方。当前在缓冲区中的文本是
"éPñi"éP<C-v>241<esc>"qpá"P
Cursor is here ----------^
除非我们将其用引号引起来,否则在那种情况下将永远不会插入“ P”,并且缓冲区是:
"éPñi"éP<C-v>241<esc>"qpá"
Cursor is here ----------^
由于我们仍在录制,因此我们可以在这里做任何想做的事情,并且在"qp
发生时将其添加到缓冲区中。因此,从这里很容易有条件地删除引号:
l " Move one character to the right. If there is no character to the right,
" then this is effectively a "break" statement, stopping playback of the recording
xx " Delete two characters (the '"P')
| " Move to the first character on this line
x " Delete one character
ÿ " End the program
Set=``;eval(";a='Set=``;eval(~;a=1;S=String.fromCharCode;q=S(34);r=Set&&q;s=S(39);alert(r+a.replace(/[^ -}]/g,q).replace(1,s+a+s)+r);~)';S=String.fromCharCode;q=S(34);r=Set&&q;s=S(39);alert(r+a.replace(/[^ -}]/g,q).replace(1,s+a+s)+r);")
注意在全新的环境中尝试每个版本(例如,新的浏览器标签)
必须至少有一种方法可以简化此过程...