Self-replicating code/quines: a fun exercise

tl:dr

A quine is a program that produces its source code as output.

I got drawn into quines and couldn’t stop for a while. I put my insights together in a (hopefully) entertaining essay.

Show me your favourite quine!

I encourage anyone to just try and implement a quine by themselves. I don’t say it’s easy. It’s not impossible either. It doesn’t necessarily require a lot of programming experience … rather a hang for riddles.

7 Likes

Here is the one I wrote for the tiny-game jam: https://github.com/haskell-game/tiny-games-hs/tree/main/prelude/quine

<insert output of (fmt <$> readFile quine.hs)><insert output of (fmt <$> readFile quine.hs)>"
-- ^ 10 ------------------------------------------------------------------- 80> --
{- prelude-10-80/quine (tristanC)
SPDX: CC0-1.0
-}

this is the output that I get. What am I doing wrong?

And what about that readFile?

I guess that happens when running the readme version, can you try with the provided quine.hs file?

1 Like

yeah that one works! But is it accessing the file system?

EDIT: ah, so I guess the code in the readme is meant to be used to create the final, minified code.

Well no, that wouldn’t be a quine otherwise :slight_smile:

1 Like

For an extra challenge use import Prelude (putStrLn) and avoid escape sequences in string literals.

One of my old university professors has an extensive page about a quine challenge (in JavaScript, but should not be that hard to adapt). He also has a bunch of hints, and a generalized challenge (with more hints):

Write a program G […]

  • that takes as input any valid […] definition of a function f that takes a string as argument, and
  • that produces as output a valid […] program P_f
  • such that the program P_f behaves like the function f applied to the program P_f itself, that is, like f(P_f).

So for the input: "f x = putStrLn x", the output should be a regular quine.

I never did get completely through it. Maybe I should try again.

1 Like

What’s the idea behind this? No functions except putStrLn?

And avoid escape sequences: this can be done rather trivially by using chr(34) for double quotes. But is this what you mean?

Yes, you’d only be allowed to use putStrLn and the base language, so no chr either.

But you can of course define your own functions.

I think the idea behind it is that it forces you to implement your own escaping mechanism.

1 Like

Here’s a quine that I would consider not using any “cheating” functions from Prelude and it also does not use the built-in string escaping mechanism:

SPOILER
escape ('%':'%':xs) = '%'  : escape xs
escape ('%':'|':xs) = '|'  : escape xs
escape ('%':'#':xs) = '#'  : escape xs
escape ('%':'$':xs) = '$'  : escape xs
escape ('#':xs)     = '"' : self ++ '"' : escape xs
escape ('|':xs)     = '\n' : escape xs
escape ('%':xs)     = '"'  : escape xs
escape ('$':xs)     = '\\' : escape xs
escape (x:xs)       = x    : escape xs
escape []           = []

self = "escape ('%%':'%%':xs) = '%%'  : escape xs|escape ('%%':'%|':xs) = '%|'  : escape xs|escape ('%%':'%#':xs) = '%#'  : escape xs|escape ('%%':'%$':xs) = '%$'  : escape xs|escape ('%#':xs)     = '%' : self ++ '%' : escape xs|escape ('%|':xs)     = '$n' : escape xs|escape ('%%':xs)     = '%'  : escape xs|escape ('%$':xs)     = '$$' : escape xs|escape (x:xs)       = x    : escape xs|escape []           = []||self = #||main = putStrLn (escape self)"

main = putStrLn (escape self)

But it still stores the whole program in a long unidiomatic string. The next step would be to factor that out into a pretty printing ADT similar to the Doc type from pretty printing libraries like this one: https://hackage.haskell.org/package/prettyprinter-1.7.1/docs/src/Prettyprinter.Internal.html#Doc.

1 Like

I will try myself first. The longer I think about Quines, the more straightforward they become … the new challenge is welcome.

1 Like

Here’s the basic idea of what I mean by this, although this is not yet a quine (it does produce a quine but the result has one very long line again):

SPOILER
data Doc = Text String | QU | BS | Self | Doc :-: Doc | Doc :|: Doc

eval :: Doc -> String
eval (Text xs) = xs
eval QU = ['"']
eval BS = ['\\']
eval Self = eval (quote self)
eval (xs :-: ys) = eval xs ++ eval ys
eval (xs :|: ys) = eval xs ++ '\n' : eval ys

quote :: Doc -> Doc
quote (Text xs) = Text "(Text " :-: QU :-: Text xs :-: QU :-: Text ")"
quote QU = Text "QU"
quote BS = Text "BS"
quote Self = Text "Self"
quote (xs :-: ys) = Text "(" :-: quote xs :-: Text " :-: " :-: quote ys :-: Text ")"
quote (xs :|: ys) = Text "(" :-: quote xs :-: Text " :|: " :-: quote ys :-: Text ")"

self = 
      Text "data Doc = Text String | QU | BS | Self | Doc :-: Doc | Doc :|: Doc"
  :|: Text ""
  :|: Text "eval :: Doc -> String"
  :|: Text "eval (Text xs) = xs"
  :|: Text "eval QU = ['" :-: QU :-: Text "']"
  :|: Text "eval BS = ['" :-: BS :-: BS :-: Text "']"
  :|: Text "eval Self = eval (quote self)"
  :|: Text "eval (xs :-: ys) = eval xs ++ eval ys"
  :|: Text "eval (xs :|: ys) = eval xs ++ '" :-: BS :-: Text "n' : eval ys"
  :|: Text ""
  :|: Text "quote :: Doc -> Doc"
  :|: Text "quote (Text xs) = Text " :-: QU :-: Text "(Text " :-: QU :-: Text " :-: QU :-: Text xs :-: QU :-: Text " :-: QU :-: Text ")" :-: QU
  :|: Text "quote QU = Text " :-: QU :-: Text "QU" :-: QU
  :|: Text "quote BS = Text " :-: QU :-: Text "BS" :-: QU
  :|: Text "quote Self = Text " :-: QU :-: Text "Self" :-: QU
  :|: Text "quote (xs :-: ys) = Text " :-: QU :-: Text "(" :-: QU :-: Text " :-: quote xs :-: Text " :-: QU :-: Text " :-: " :-: QU :-: Text " :-: quote ys :-: Text " :-: QU :-: Text ")" :-: QU
  :|: Text "quote (xs :|: ys) = Text " :-: QU :-: Text "(" :-: QU :-: Text " :-: quote xs :-: Text " :-: QU :-: Text " :|: " :-: QU :-: Text " :-: quote ys :-: Text " :-: QU :-: Text ")" :-: QU
  :|: Text ""
  :|: Text "self = " :-: Self
  :|: Text ""
  :|: Text "main = putStrLn (eval self)"

main = putStrLn (eval self)

I need a better pretty printer.

Little late to the party but here is a quine of order two I wrote many years ago in Haskell.

1 Like