We're planting a tree for every job application! Click here to learn more

An Interactive Quine in Clojure

Yehonathan Sharvit

11 Mar 2019

•

2 min read

An Interactive Quine in Clojure
  • Clojure

According to Wikipedia, a quine is a non-empty computer program which takes no input and produces a copy of its own source code as its only output. In other words, a quine is a code snippet whose output is exactly the same as its source code.

Quine Blog.png

In the Clojure world, we would say that a quine is a code expression that evaluates to itself.

We say code expression in opposition with data expressions that trivially update to themselves:

42
; 42

[1 2 42]
;[1 2 42]

TL;DR

If you have no patience to read this article, here is the simplest Clojure Quine:

((fn [x] (list x (list 'quote x))) '(fn [x] (list x (list 'quote x))))

Indeed, the output is exactly the same as the source code.

I hope that now you are motivated to learn, step by step, how we this quine was discovered.

Quine: first attempt

Like we wrote before, a quine is a piece of code that evaluates to itself. As a first attempt, we might be tempted to try to write a function that returns its source code as a form. After all, Clojure is homoiconic: the structure of the code is the same as the structure of the data.

Let’s try to write an anonymous function with no arguments that returns its code as a quoted form. This function does nothing so its code should be (fn []). So let’s write and call an anonymous function that returns '(fn []):

((fn [] '(fn [])))

The problem is that now our anonymous function doesn’t do nothing. In fact, it returns '(fn []). So the body of the function is now '(fn []).

No problem, let’s improve our anonymous function so that it returns '(fn [] '(fn [])):

((fn [] '(fn [] '(fn []))))

But now, the problem is that our anonynous function returns '(fn [] '(fn []).

This strategy is not going to work: we will always be missing a (fn []) wrapping level.

Quine: self referentiality

You might already have guessed that a real quine is going to involve self-referentiality.

Let’s find a function f and an argument x such that such that (f x) is exactly (f x).

A good guess for x is 'f.

So let’s write our function f such that (f 'f) is (f 'f):

(defn f [x] '(f 'f))
(f 'f)

It works! (f 'f) indeed evaluates to itself.

The only problem is that our code contains the definition of f but our output doesn’t.

In order to overcome this issue, we need to define f as an anonymous function.

As a first step, let’s rewite f in such a way that it will return (f 'f) not for all the arguments but only when we pass 'f to f:

(defn f [x] (list x (list 'quote x)))
(f 'f)

Finally if we replace f by its definition, we get our quine:

((fn [x] (list x (list 'quote x))) '(fn [x] (list x (list 'quote x))))

Do you feel a headache?

That’s normal: self-referentiality is very often a dizzy activity. ​ ​ If you want to learn more about Clojure, start reading my Get Programming with Clojure book today! By the time you finish your final capstone project, you’ll be designing Clojure functions, apps, and libraries like a pro!

Did you like this article?

Yehonathan Sharvit

Full-Stack Web Consultant. Expert in Clojure, ClojureScript and Javascript.

See other articles by Yehonathan

Related jobs

See all

Title

The company

  • Remote

Title

The company

  • Remote

Title

The company

  • Remote

Title

The company

  • Remote

Related articles

JavaScript Functional Style Made Simple

JavaScript Functional Style Made Simple

Daniel Boros

•

12 Sep 2021

JavaScript Functional Style Made Simple

JavaScript Functional Style Made Simple

Daniel Boros

•

12 Sep 2021

WorksHub

CareersCompaniesSitemapFunctional WorksBlockchain WorksJavaScript WorksAI WorksGolang WorksJava WorksPython WorksRemote Works
hello@works-hub.com

Ground Floor, Verse Building, 18 Brunswick Place, London, N1 6DZ

108 E 16th Street, New York, NY 10003

Subscribe to our newsletter

Join over 111,000 others and get access to exclusive content, job opportunities and more!

© 2024 WorksHub

Privacy PolicyDeveloped by WorksHub