~kris/9p

krisyotam.net

krisyotam.net/reference/pmikkelsen/pmikkelsen.com/haskell/quine.html -rw-r--r-- 8.8 KiB
8bfa4b74 — Kris Yotam ci: declare SourceHut source for push builds a month ago
                                                                                
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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
<!DOCTYPE HTML>
<html>
<head>

    <title>haskell - quine</title>
    <style media="screen, handheld">
body { display: flex; flex-wrap: wrap; font-family: sans;}
header { flex-basis: 100%; flex-shrink: 0; }
article { flex-basis: 60%; padding-left: 1em; }
footer { flex-basis: 100%; flex-shrink: 0; }
header nav { display: flex; justify-content: space-between; }
nav a, header a { text-decoration: none ; color: inherit; }
header h1 span { margin-left: 1em; font-size: 50%; font-style: italic; }
.mainContent > nav { flex-basis: content; padding-right: 1vw; min-width: 16em; }
nav ul { display: flex; flex-direction: column; list-style-type: none; list-style-position: outside; padding-left: 0;  }
nav li ul { padding-left: 0.6em }
footer { display: flex; justify-content: space-between; }

/* cut here to leave vanity behind */

body { margin:0; padding: 0; font-size: 84%; font-family: Helvetica, Verdana, Arial, 'Liberation Sans', FreeSans, sans-serif; }
a { text-decoration: none; color: }
a:hover { text-decoration: underline; }
.thisPage { color: black; }

/* header and top bar */
header nav { background-color: rgb(100,135,220); color: white; padding: 0.3em; border-bottom: 2px solid black; font-size: 91%; }
header h1 { background-color: #ff6d06; color: black; margin: 0; border-bottom: 2px solid black; font-weight: normal; padding: 0.25ex; font-size: 233%; }
header a:hover { text-decoration: none; }

/* sidebar */
.mainContent > nav { border-right: 1px solid #ddd; padding: 0;  } 
.mainContent > nav > div { border-bottom: 1px solid #ddd; } 
.mainContent > nav > div a { color: rgb(0, 102, 204); display: block; text-transform: capitalize; font-weight: bold; padding: 0.25em 1ex 0.25em 2mm; font-size: 102%} 
.mainContent > nav > div a:hover { color: white; background-color: rgb(100,135,220); border-left: black solid 0.2em; text-decoration: none; }
.mainContent > nav > div p { font-weight: bold; margin: 0 0 0.5em 2mm; padding: 1em 0 0 0; }

/* main copy */
article { padding: 0.5ex 0 5vh 1vw;  }
article h1, article h2 { color: rgb(0,102,204); font-weight: bold; margin: 2em 0 0 0; border-bottom: 2px solid rgb(0,102,204); }
article h3, article h4, article h5 { color: rgb(0,102,204); font-weight: bold; margin: 2em 0 0 0; }
article h6, article h7, article h8 { color: rgb(0,102,204); font-weight: bold; margin: 2em 0 0 0; }
article a { color: rgb(0,102,204); }
article a:hover { color:  rgb(100,135,220); }
article pre { font-size: 1.2em; }

/* footer */
footer { color: white; background-color: rgb(100,135,220); }
footer a { color: inherit; }
footer div { padding: 1em; }

/* tables */
table { border: 1px solid rgba(128,128,128,0.5); padding: 0; }
th { color: white; background-color: rgb(100,135,220); }
tr:nth-child(odd) { background-color: rgba(128,128,128,0.1)  }

/* modifications */
img {
	max-width: 100%;
	border: 1px solid black;
}

body {
	
}

header h1 {
	background-color: #c2d2c6;
}

html {
	font-size: 1.2em;
}

header nav, footer {
	background-color: #442a13;
}

code > pre {
	border: 2px solid #442a13;
	background-color: #c2d2c6;
	width: max-content;
	padding: 0 0.5em;
}

.mainContent > nav > div a, article a:hover {
	color: #442a13;
}

.mainContent > nav > div a:hover {
	color: #442a13;
	background-color: #c2d2c6;
}

article h1, article h2 {
	color: #c48f3b;
	border-bottom: 2px solid #442a13;
}

article a, .thisPage, footer, header nav {
	color: #c48f3b;
}

footer {
	padding: 0.5em;
	flex-shrink: 1;
	flex-basis: unset;
}

header {
	flex-basis: unset;
}

html {
	display: flex;
	min-height: 100%;
}

body {
	flex-direction: column;
	flex: 1;
	background-color: #e3dfd7;
}

.mainContent {
	display: flex;
	flex-grow: 1;
}    </style>
    <link rel="shortcut icon" href="https://images.pmikkelsen.com/favicon.ico" type="image/vnd.microsoft.icon">
    <meta charset="UTF-8">
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> 



    

</head>
<body>

<header>
    <nav>
    <div class="left">
		<a href="https://pmikkelsen.com">notes</a> |
		<a href="https://git.pmikkelsen.com">git</a> |
		<a href="https://images.pmikkelsen.com">images</a> |
		<a href="https://files.pmikkelsen.com">files</a> |
		<a href="https://prolog.pmikkelsen.com">PProlog</a> |
		<a href="https://apl.pmikkelsen.com">APL9</a> |
		<a href="https://aplwc.org">aplwc</a>
    </div>

    <div class="right">
		<a href="https://git.sr.ht/~pmikkelsen">sourcehut</a> |
		<a href="https://9front.org">9front</a> |
		<a href="https://openbsd.org">OpenBSD</a> |
		<a href="https://dyalog.com">Dyalog</a>
    </div>

    </nav>
    <h1><a href="../index.html">Peter&#39;s website <span id="headerSubTitle">- random notes</span></a></h1>
</header>

<div class=mainContent>
    <nav id="side-bar">
        <div>
<ul>
<li><a href="../APL-and-J/index.html">&rsaquo; APL and J/</a></li>
<li><a href="../OpenBSD/index.html">&rsaquo; OpenBSD/</a></li>
<li><a href="../contact.html">&rsaquo; contact</a></li>
<li><a href="../facts/index.html">&rsaquo; facts/</a></li>
<li><a href="index.html" class="thisPage">&raquo;<i> haskell/</i></a></li>
<li><ul>
<li><a href="quine.html" class="thisPage">&raquo;<i> quine</i></a></li>
</ul></li>
<li><a href="../linux/index.html">&rsaquo; linux/</a></li>
<li><a href="../mainframe/index.html">&rsaquo; mainframe/</a></li>
<li><a href="../me/index.html">&rsaquo; me/</a></li>
<li><a href="../opinions/index.html">&rsaquo; opinions/</a></li>
<li><a href="../plan9/index.html">&rsaquo; plan9/</a></li>
<li><a href="../prolog/index.html">&rsaquo; prolog/</a></li>
<li><a href="../web/index.html">&rsaquo; web/</a></li>
</ul>
        </div>
    </nav>

<article>
<p>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.</p>
<h2>First attempt</h2>
<p>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 <code>quine.hs</code>. The code for hello world looks like this</p>
<code><pre>
main = putStrLn "Hello world!"
</pre></code>
<p>When this is run using runhaskell quine.hs, it produces the output</p>
<code><pre>
Hello world!
</pre></code>
<p>Well, not quite a quine yet but we are getting something to the screen at least ;)</p>
<h2>Second attempt</h2>
<p>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</p>
<code><pre>
main = putStrLn code
  where code = "main = putStrLn code\n  where code = ???"
</pre></code>
<p>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</p>
<code><pre>
main = putStrLn code
  where code = "main = putStrLn code\n  where code = "
</pre></code>
<p>And it outputs</p>
<code><pre>
main = putStrLn code
  where code =
</pre></code>
<p>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 <code>\n</code> shown as newlines.</p>
<h2>Third attempt</h2>
<p>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 <code>print</code>, which prints the output using the <code>show</code> function instead of interpreting the string. We would want to both print it as before, and to print it using <code>print</code>, so we change our main to be <code>main = putStrLn code >> print code</code>, and update our string to include the print. The code then becomes</p>
<code><pre>
main = putStrLn code >> print code
  where code = "main = putStrLn code >> print code\n  where code = "
</pre></code>
<p>And it outputs</p>
<code><pre>
main = putStrLn code >> print code
  where code =
"main = putStrLn code >> print code\n  where code = "
</pre></code>
<p>So close! The only problem is that the <code>putStrLn</code> append a newline after the output, which we don't want in this case.</p>
<h2>Final attempt</h2>
<p>The simple fix is just to use <code>putStrLn</code>'s little brother <code>putStr</code> which doesn't print that newline. The final program is then</p>
<code><pre>
main = putStr code >> print code
  where code = "main = putStr code >> print code\n  where code = "
</pre></code>
<p>And luckily it outputs exactly itself</p>
<code><pre>
main = putStr code >> print code
  where code = "main = putStr code >> print code\n  where code = "
</pre></code>

</article>
</div>

<footer>
<a href="http://werc.cat-v.org">Powered by werc</a> © Peter Mikkelsen 2019-2025
</footer>
</body></html>