Quote-Safe Quines
Python 2 3, 181 152 130 124 122 bytes
""" """>" "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)#
Try it online! The TIO comes with a header and footer that automatically test the validity of the quine. You can clear them to just run the quine.
This code works by using the triple-quoted strings in Python. """ """
is equal to ' '
and """" """
is equal to '" '
.
The code does use exec
, but not for the "non-quiney" way of executing data as code, just for setting a variable from inside an expression. The exec
is properly encoded in the data, too.
The first statement compares the string, possibly with a quote prepended, to " "
, and sets the variable oct
accordingly. (The variable could've been any short builtin.)
The rest of the code then implements the traditional Python quine using %r
string formatting, with some additional code that strips the extra quotes if oct
is unchanged.
An alternative version using the "cheaty" exec
comes in at 126 bytes with less repeated code:
""" """>" "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)#
Try it online!
V, 27, 23 bytes
éPñi"éP241"qpá"lxx|xÿ
Try it online!
Since this contains some unprintable characters, here is a readable version:
éPñi"éP<C-v>241<esc>"qpá"lxx|xÿ
and here is a hexdump:
00000000: e950 f169 22e9 5016 3234 311b 2271 70e1 .P.i".P.241."qp.
00000010: 226c 7878 7c78 ff "lxx|x.
So the very first thing we need to do is to determine if the first character is a quote. éP
inserts a 'P' character, but "éP
is a NOOP. After that, we run a slight modification on the standard extendable quine, which is:
ñi<C-v>241<esc>"qpÿ
We're going to do it slightly differently though. First off we need to insert the starting "éP" text. So we do
ñ " 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 '"'
Here is where the branching happens. The text currently in the buffer is
"éPñi"éP<C-v>241<esc>"qpá"P
Cursor is here ----------^
Unless we wrapped it in quotes, in that case the 'P' would never have been inserted, and the buffer is:
"éPñi"éP<C-v>241<esc>"qpá"
Cursor is here ----------^
Since we are still recording, we can do whatever we want here, and it will get added to the buffer when the "qp
happens. So from here it's pretty easy to conditionally delete the quotes:
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
StandardML, 182 176 108 bytes
";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))
Unquoted version: Try it on codingground.
Quoted version: Try it on codingground.
Note that the output looks something like this
> val it = "{some string}" : string
> val it = "{some string}" : string
{output to stdout}> val it = fn : string -> unit
because the code is interpreted declaration by declaration (each ;
ends a declaration) and shows the value and type of each declaration.
Background
In SML there is a quine of the form <code>"<code in quotes>"
:
str(chr 34);(fn x=>print(x^it^x^it))"str(chr 34);(fn x=>print(x^it^x^it))"
and one in the form "<code in quotes>"<code>
:
";str(chr 34)^it;print(it^it)";str(chr 34)^it;print(it^it)
Both rely on the fact that the <code>
-part contains no quotes and can thus be quoted with out the need for escaping anything, the "
needed to output the quine are given by str(chr 34)
.
They also heavily rely on the implicit identifier it
which is used when no explicit identifier is given in a declaration.
In the first quine str(chr 34);
binds it
to the string containing "
, fn x=>
starts an anonymous function taking one argument x
, then concatenates x^it^x^it
and prints the resulting string. This anonymous function is directly applied to a string containing the program code, so the concatenation x^it^x^it
yields <code>"<code>"
.
The second quine starts with just the program code as string ";str(chr 34)^it;print(it^it)";
which is bound to it
. Then str(chr 34)^it;
concatenates a quote to the start of the string and as again no explicit identifier is given, the resulting string "<code>
is bound to it
. Finally print(it^it)
concatenates the string with itself yielding "<code>"<code>
which is then printed.
Explanation
Edit: No longer up to date with the 108-byte version, however one might understand it too after reading this explanation.
The quote-safe quine combines both of the above approaches and is itself of the form "<code>"<code>
. Putting this in again in quotes yields ""<code>"<code>"
, so we get an empty string and then a quine of the other form.
That means the program is either given its own source in the form "<code>
by the identifier it
, or it
is just "
and we are given our own source <code>
as argument and must thus be a function which handles such an argument.
(if size it>1then(print(it^it);fn _=>())else fn x=>print(it^it^x^it^x^it))
To identify in which case we are, we check whether the size of it
is larger than 1. If not then it
is "
and we are in the second case, so the else
-part returns an anonymous function fn x=>print(it^it^x^it^x^it)
which is then called because its followed by source as string. Note the leading it^it^
which is needed for the empty string at the start of the of the program.
If size it
is larger than 1 we are in the then
-part and just perform print(it^it)
, right? Not quite, because I neglected to tell you that SML is strongly typed which means that a conditional if <cond> then <exp_1> else <exp_2>
must always have the same type which again means that the expressions <exp_1>
and <exp_2>
need to have the same type. We already know the type of the else
part: An anonymous function which takes a string and then calls print
has type string -> <return type of print>
, and print
has type string -> unit
(unit
is in some way similar to void
in other languages), so the resulting type is again string -> unit
.
So if the then
part was just print(it^it)
which has type unit
, we would get a type mismatch error. So how about fn _=>print(it^it)
? (_
is a wildcard for an argument that is not used) This anonymous function on its own has type 'a -> unit
where 'a
stands for an arbitrary type, so in the context of our conditional which enforces a string -> unit
type this would work. (The type variable 'a
gets instantiated with type string
.) However, in this case we would not print anything as the anonymous function is never called! Remember, when we go in the then
-part the overall code is "<code>"<code>
, so the <code>
-part evaluates to a function but, as nothing comes after it, its not called.
Instead we use a sequentialisation which has the form (<exp_1>; ...; <exp_n>)
where <exp_1>
to <exp_n-1>
may have arbitrary types and the type of <exp_n>
provides the type of the whole sequentialisation. From a functional point of view the values of <exp_1>
to <exp_n-1>
are simply discarded, however SML also supports imperative constructs so the expressions may have side effects. In short, we take (print(it^it);print)
as the then
-part, thus printing first and then returning the function print
which has the correct type.