Skip to content

Instantly share code, notes, and snippets.

@gituser768
Last active December 14, 2023 10:52
Show Gist options
  • Save gituser768/51580d5699876c1a6cd4 to your computer and use it in GitHub Desktop.
Save gituser768/51580d5699876c1a6cd4 to your computer and use it in GitHub Desktop.
A quine written in Clojure with a brief explanation of how I wrote it

Quines.

A quine is a program which produces its own sourcecode as its output. Typically, the trick is to use a format string with a call to a print or printf function. Since lisps can easily treat sourcecode as any other data, writting a quine in lisp is not as mind-bending an excersise as in other languages (see the examples here). Additionally, access to anonymous functions in Clojure makes it easy to get the recursion required for a quine.

Approach

Writing a quine initially seems a daunting task, but once it's broken down a bit, it becomes surprisingly easy. Armed with lambdas and syntax quoting, all we need to do is write a function which returns the argument passed to it wrapped in lambda syntax, and applied to the argument wrapped in syntax quoting.

Implementation

I initially wrote this using the special form backtick and unquoting with ~ but then remembered that Clojure gives the namespace qualified symbols when these are nested within each other (try implementing the below code using these symbols instead of quote to see that it won't implement a proper quine since the actual syntax will be different even though they will be evaluated in the same way). See this article on syntax quoting from 8th Light for a really good explanation of quoting in Clojure.

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

I use quote and list to wrap the argument with (fn [x] *arg*) and then use another list call to create a list which applies this function on the quoted form of the argument. I use (quote quote) to quote out a call to quote. This is needed so that the symbol quote is passed rather than the result of evaluating quote. After this function was written, I just copied it and passed it as a quoted argument to the function.

Putting some better indentation into the code:

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

Overall this was a good excersise in syntax quoting, recursive reasoning and useless problem solving. Highly recommended!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment