There are currently no projects
This tab is intentionally left blank.
Quines are a wonderful thing. A quine is a program, that when run produces its own code as output. Now, in most interpreted languages you can read your own code through means of I/O — I’d consider that cheating: We can do much better than that. We’ll do it without anything but a clever theoretical result. (And maybe a little bit of code to make it work in practice.)
You can make a quine in any Turing-complete language, and the reason for this is a thorem called the recursion theorem. The theorem (informally[1]) states, that for any computable function f of two inputs, it is possible to create a program R that computes the function r defined by , where
is the description — or source code, if you will — of R. In essence this means, that it is possible to write a program which obtains its own source code, and then uses it for further computation.
Now, in order for this post to make sense, we’ll have to look a bit into the proof of the theorem. The idea behind the proof is as follows: We divide our program into three program fragments, A, B and F, each of which we can think of as a function in our programming language of choice. A is called first, and has the task of getting , the source code of the functions B and F, and passing this on to B. B computes
, and uses this to compute
and pass it on to F. F is then the program fragment computing the function f, now with the source code of the entirety of the program in hand.
The interaction between A, B and F
Now that we have an idea of how the different fragments are to interact with each other, we need to get down to the specifics, and actually construct the fragments A and B[2].
We will start by constructing A. Let us for a moment assume that we actually have B and F already constructed. In that case, is a fixed string. This means, we can have A simply call
and be done with it.
For constructing B we will need to be a bit more tricksy. We know, based on how we constructed A, exactly what A looks like if we know what is[3]. This means, given
, we can construct
— and we’re in luck: Remember, when A calls B, it passes along the extra information of
. So, we now have both
and
, and if we compose these two we get
. We now call
, and B does what we want it to.
This concludes the proof of the theorem, and it is now time to look a bit at how we can use it. A particularily interesting thing about this proof is, that we can use this construct directly to create a quine. To try this out, let us create a SML program, which prints its own source code in reverse.
We can start by creating F. All that F needs to do is simply to reverse and then print its input. This can be achieved pretty easily like so:
val F = print o implode o rev o explode
Next up is B, but before we can construct that, we need to figure out what we want A to look like. The simplest option is to have A take on the following form:
fun A () = B "fun B x = ... and F x = ..."
Now we can begin constructing B. If we just naïvely do this, we get something to the tune of:
fun B x = F ("fun A x = B \"" ^ x ^ "\"\n" ^ x)
This, however, suffers from the fact, that we’ll need to escape the quotes in the definition of B when writing them inside of the string in A. Were we to do this, we’d find that we’d need to escape the escape characters as well. A fixed version looks as follows:
fun B x = let fun esc (#"\""::xs) = #"\\" :: #"\"" :: esc xs
| esc (#"\\"::xs) = #"\\" :: #"\\" :: esc xs
| esc (x::xs) = x :: esc xs
| esc [] = []
in F ("fun A x = B \"" ^ (implode o esc o explode) x ^ "\"\n" ^ x) end
Finally, we need to create A, but that is fairly simple, as we already have determined what format it should have. Since SML doesn’t support multiline strings, however, I collapse B and F onto one line, giving us a final result of:
(* With B and F neatly formatted *)
fun A () = B "and B x = let fun esc (#\"\\\"\"::xs) = #\"\\\\\" :: #\"\\\"\" :: esc xs | esc (#\"\\\\\"::xs) = #\"\\\\\" :: #\"\\\\\" :: esc xs | esc (x::xs) = x :: esc xs | esc [] = [] in F (\"fun A () = B \\\"\" ^ (implode o esc o explode) x ^ \"\\\"\\n\" ^ x) end and F x = (print o implode o rev o explode) x"
and B x = let fun esc (#"\""::xs) = #"\\" :: #"\"" :: esc xs
| esc (#"\\"::xs) = #"\\" :: #"\\" :: esc xs
| esc (x::xs) = x :: esc xs
| esc [] = []
in F ("fun A () = B \"" ^ (implode o esc o explode) x ^ "\"\n" ^ x) end
and F x = (print o implode o rev o explode) x
(* And with B and F collapsed *)
fun A () = B "and B x = let fun esc (#\"\\\"\"::xs) = #\"\\\\\" :: #\"\\\"\" :: esc xs | esc (#\"\\\\\"::xs) = #\"\\\\\" :: #\"\\\\\" :: esc xs | esc (x::xs) = x :: esc xs | esc [] = [] in F (\"fun A () = B \\\"\" ^ (implode o esc o explode) x ^ \"\\\"\\n\" ^ x) end and F x = (print o implode o rev o explode) x"
and B x = let fun esc (#"\""::xs) = #"\\" :: #"\"" :: esc xs | esc (#"\\"::xs) = #"\\" :: #"\\" :: esc xs | esc (x::xs) = x :: esc xs | esc [] = [] in F ("fun A () = B \"" ^ (implode o esc o explode) x ^ "\"\n" ^ x) end and F x = (print o implode o rev o explode) x
And there we have it, we’ve created a lovely[4] reverse quine in SML using the recursion theorem. Not only that, we could repeat the process and do the exact same thing in most any other language — or change out F to whatever we wish. There is nothing special about the language or F we chose — and that I find quite spectacular.