Iterating quine

From Esolang
Jump to navigation Jump to search

An iterating quine is a sequence of different programs (preferably in different languages) in which the output of one program in the sequence is the source of the next.

If the sequence is N programs long, the source of program i is S(i) and the output of program i is O(i), then O(i) = S(i+1) and O(N) = S(1).

Constructing an iterating quine

Iterating quines are often easier to construct than regular quines in some of the involved languages would be – only one of the languages involved needs any level of computational power, the others just need to be able to print strings. The simplest way to construct an iterating quine is to choose one language as the "seed language", and find or write a universal quine constructor for that language (a universal quine constructor will, for any function f, produce a piece of code that outputs function f of its own source code; universal quine constructors are normally about as easy to write as quines). Then, for each language L involved in the iterating quine, write a function in the seed language that takes a string S as input, and produces a program in language L that prints S. The iterating quine can then be constructed via taking the function composition of all the functions written in the previous step, and using it as the f of the universal quine constructor.

Example

Here's a universal quine constructor in Perl 5 (where the function f is defined as sub f{$_[0]}, the identity function, producing a regular quine):

$x=;eval $x
__DATA__
sub f{$_[0]} print f("\$x=;eval \$x\n__DATA__\n$x")

Now we can write a Perl 5 function f that takes a string and produces a Python 2 function that prints that string (the function outputs print """, followed by its argument minus its trailing newline with a backslash inserted before every backslash and double quote, followed by """):

sub f{chomp $_[0];'print """'.($_[0]=~s/(?=[\\"])/\\/rg).'"""',$/}

and if we give that function to the universal quine constructor, we get the following iterating quine between Perl 5 and Python 2:

$x=;eval $x
__DATA__
sub f{chomp $_[0];'print """'.($_[0]=~s/(?=[\\"])/\\/rg).'"""',$/} print f("\$x=;eval \$x\n__DATA__\n$x")

The output of this program is the following Python 2 program (i.e. f of the original program):

print """$x=;eval $x
__DATA__
sub f{chomp $_[0];'print \"\"\"'.($_[0]=~s/(?=[\\\\\"])/\\\\/rg).'\"\"\"',$/} print f(\"\\$x=;eval \\$x\\n__DATA__\\n$x\")"""

and the output of that program is the original Perl 5 program, thus giving us an order-2 iterating quine.

For an order-3 iterating quine, we can use the same trick to escape the program's source code twice. For example, here's an order-3 iterating quine from Perl 5 via JavaScript and Python 2:

{undef $/; $x=}
eval $x
__DATA__
sub e {
  my $x = shift;
  $x =~ s/\n\z//;
  $x =~ s/(?=[\\"])/\\/g;
  $x =~ s/\n/\\n/g;
  $x
}
sub f {
  $_ = $_[0];
  $_ = 'print "'.e($_).'"'.$/;
  $_ = 'console.log("'.e($_).'")'.$/;
}
print f("{undef \$/; \$x=}\neval \$x\n__DATA__\n$x")

e is a helper function that escapes a string (minus its final newline, as many languages print a newline after printing output). We can use that to write escaping statements for Python 2 ($_ = 'print "'.e($_).'"'.$/;) and JavaScript ($_ = 'console.log("'.e($_).'")'.$/;); using the composition of these two statements as the body of the function f gives us the iterating quine we need.

Note that no knowledge is needed about Python or JavaScript to write this iterating quine, except for the syntax of print statements and of string literals; all the real work is done in Perl. That means that iterating quines can easily be sent via non-Turing complete languages, or languages that the author does not know well, as long as they are familiar with at least one language in the loop.

See also

External resources