tags:

views:

227

answers:

6

I'm looking for the ability to have the REPL print the current definition of a function. Is there any way to do this?

For example, given:

(defn foo [] (if true "true"))

I'd like to say something like

(print-definition foo)

and get something along the lines of

(foo [] (if true "true"))

printed.

A: 

my origional answer was wrong, Thanks Isaac for introducing the source function! some of the explanation may still be helpful.

when you define a function anywhere (on the repl or in an ide) it gets compiled into a class that implements the iFN interface and the class is then loaded into the JVM and saved in a var in the current namespace so you can find it again to call it. (this is the super short version). each function is it's own compiled class

when you call a function by it's name you are actually getting the class out of the var and calling the invoke() method of that class. the original code is already lost (if it was written in clojure to start with).

What you could do is write your own defn that saves a copy of the deffiniton into the function's meta-data so that you can read that meta-data later. This sort of gives you what you want though only for functions you define yourself. use the source function.

Arthur Ulfeldt
+9  A: 

You'll want to import the repl namespace, and use the source function from it:

(ns myns
    (:use [clojure.repl :only (source)]))
(defn foo [] (if true "true"))
(source foo)

=> (foo [] (if true "true"))
    nil

Though this wouldn't work in the REPL, only where the function is defined in a .clj file on the classpath. Which doesn't answer your question, then: you'd need to have a defn that stores, in the metadata of the fn it defines, the source of the function. Then you'd write a function that recalls that bit of metadata. That shouldn't be terribly difficult.

Isaac Hodes
+3  A: 

I asked exactly this question on the Clojure mailing list recently and the answers included overriding parts of the REPL to stash the input (and output) away for future reference as well as an override of defn to store the source in metadata (which you could then easily retrieve in the REPL).

Read the thread on the Clojure mailing list

Sean Corfield
+4  A: 
Arthur Edelstein
+2  A: 

An alternative to source (which should be available when starting a REPL, as of 1.2.0. If not, it's in clojure.repl. If you're working with 1.1.0 or lower, source is in clojure.contrib.repl-utils.), for REPL use, instead of looking at functions defined in a .clj file:

(defmacro defsource
  "Similar to clojure.core/defn, but saves the function's definition in the var's
   :source meta-data."
  {:arglists (:arglists (meta (var defn)))}
  [fn-name & defn-stuff]
  `(do (defn ~fn-name ~@defn-stuff)
       (alter-meta! (var ~fn-name) assoc :source (quote ~&form))
       (var ~fn-name)))

(defsource foo [a b] (+ a b))

(:source (meta #'foo))
;; => (defsource foo [a b] (+ a b))

If you wanted the above to show (defn foo [a b] (+ a b)), you could use:(clojure.walk/postwalk-replace {'defsource 'defn} (:source (meta #'foo))). (you'd probably put this in defsource, or at least in print-definition, though. I wouldn't do either.)

A simple print-definition:

(defn print-definition [v]
  (:source (meta v)))

(print-definition #'foo)

#' is just a reader macro, expanding from #'foo to (var foo):

(macroexpand '#'reduce)
;; => (var reduce)
MayDaniel
+1  A: 

Clojure doesn't have a decompiler, so that means there's no way to get at the source of an arbitrary function unless it was a defn loaded from disk. However, you can use a neat hack called serializable-fn to create a function that has its source form stored in its metadata: http://github.com/Seajure/serializable-fn

The defsource answer is very similar to this, but this solution works with arbitrary fns, not just top-level defns. It also makes fns print prettily at the repl without a special printing function.

technomancy