Thursday, November 15, 2012

Clojure makes quines way too easy

A popular programming challenge is to, in your favorite programming language, write a Quine -- a program/function that prints its own source code.  Usually, writing a Quine is an incredibly mindbending effort.  However, yesterday, it was pointed out to me that in Clojure, this task is ridiculously simple:

(defn self-source
  "prints the source of itself"
  []
  (source self-source))

Where's the challenge in that?  :-)

6 comments:

  1. No it doesn't!


    user=>
    (defn self-source
    "prints the source of itself"
    []
    (source self-source))
    #'user/self-source
    user=> (self-source)
    Source not found
    nil
    user=>

    ReplyDelete
  2. The source function doesn't work on functions defined interactively the REPL. Put it in a file, and send the contents of your file to the REPL, and self-source will work just fine. (I tested this in Eclipse with the Counterclockwise plug-in, on Clojure 1.4.0)

    Reason it works: When you send the entire contents of the file to the REPL, the metadata gets annotated with the line number where the function is defined. source uses that information to get at the source code.

    ReplyDelete
  3. This comment has been removed by the author.

    ReplyDelete
  4. Using an API to access the source form a the function's code has never been a valid way to define a quine. Equally invalid are "quines" that make a call to copy the source file for the code (with or without using metadata for the path).

    A quine in any LISP has always been fairly trivial. For Clojure just replace lambda with fn:

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

    You can make it a bit more idiomatically Clojure thusly:

    (#(list % (list (quote quote) %)) '#(list % (list (quote quote) %)))

    Which gives an expansion that is a true quine:

    ((fn* [p1__20#] (list p1__20# (list (quote quote) p1__20#))) (quote (fn* [p1__20#] (list p1__20# (list (quote quote) p1__20#)))))

    ReplyDelete
  5. Shorter yet:

    (#(list % (list 'quote %)) '#(list % (list 'quote %)))

    Evaluates to the quine:

    ((fn* [p1__48#] (list p1__48# (list (quote quote) p1__48#)))
    (quote (fn* [p1__48#] (list p1__48# (list (quote quote) p1__48#)))))

    ReplyDelete
  6. @28:10 "It's Quine Time"
    http://www.infoq.com/presentations/miniKanren
    https://github.com/webyrd/quines

    ReplyDelete