summaryrefslogtreecommitdiff
path: root/sites/pmikkelsen.com/haskell/quine.md
blob: f95214546bd33828007e5de2c6f7ca8212f51e6a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
Today I am going to go through the process of writing a small program
which prints its own source when executed. These kinds of programs are
also called quines, and I suggest that you try it out on your own if you
haven't already done so, as it is a very fun little problem! So if you
don't want any spoilers, please leave this page now and come back later.


## First attempt

Okay, so first of let's just write a small hello world program to get
things going. All our code will be in a file called `quine.hs`. The code
for hello world looks like this


	main = putStrLn "Hello world!"


When this is run using runhaskell quine.hs, it produces the output


	Hello world!


Well, not quite a quine yet but we are getting something to the screen
at least ;)

## Second attempt

Now we get the idea that we copy the entire program's source into a
string and print that string instead. To do this, the code could look
something like this


	main = putStrLn code
	  where code = "main = putStrLn code\n  where code = ???"


Here we run into a problem, since we can't include the entire code into
the string. Copying everything we can into the string just increases
the size of the string itself, which means that there is now even more
to copy! We start by only copying all the code upto the string and see
how it looks when executed. The code is now


	main = putStrLn code
	  where code = "main = putStrLn code\n  where code = "


And it outputs

	main = putStrLn code
	  where code =

Quite good! Now if we could only include the string itself in its printed form, with the quotes and all, and not the interpreted form with `\n` shown as newlines.

## Third attempt

After looking through the haskell standard libraries for a bit, we find
a function that looks promising for what we want to do. This function is
`print`, which prints the output using the `show` function instead of
interpreting the string. We would want to both print it as before, and
to print it using `print`, so we change our main to be `main = putStrLn
code >> print code`, and update our string to include the print. The
code then becomes

	main = putStrLn code >> print code
	  where code = "main = putStrLn code >> print code\n  where code = "

And it outputs


	main = putStrLn code >> print code
	  where code =
	"main = putStrLn code >> print code\n  where code = "


So close! The only problem is that the `putStrLn` append a newline after
the output, which we don't want in this case.

## Final attempt

The simple fix is just to use `putStrLn`'s little brother `putStr`
which doesn't print that newline. The final program is then


	main = putStr code >> print code
	  where code = "main = putStr code >> print code\n  where code = "

And luckily it outputs exactly itself


	main = putStr code >> print code
	  where code = "main = putStr code >> print code\n  where code = "