Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I trace code execution in Clojure?

Why learning Clojure, I sometimes need to see what a function does at each step. For example:

(defn kadane [coll]
   (let [pos+ (fn [sum x] (if (neg? sum) x (+ sum x)))
         ending-heres (reductions pos+ 0 coll)]
     (reduce max ending-heres)))

Should I insert println here and there (where, how); or is there a suggested workflow/tool?

like image 442
blackened Avatar asked Nov 28 '22 16:11

blackened


2 Answers

This may not be what you're after at the level of a single function (see Charles Duffy's comment below), but if you wanted to do get an overview of what's going on at the level of a namespace (or several), you could use tools.trace (disclosure: I'm a contributor):

(ns foo.core)

(defn foo [x] x)
(defn bar [x] (foo x))

(in-ns 'user) ; standard REPL namespace

(require '[clojure.tools.trace :as trace])
(trace/trace-ns 'foo.core)

(foo.core/bar 123)
TRACE t20387: (foo.core/bar 123)
TRACE t20388: | (foo.core/foo 123)
TRACE t20388: | => 123
TRACE t20387: => 123

It won't catch inner functions and such (as pointed out by Charles), and might be overwhelming with large code graphs, but when exploring small-ish code graphs it can be quite convenient.

(It's also possible to trace individually selected Vars if the groups of interest aren't perfectly aligned with namespaces.)

like image 104
Michał Marczyk Avatar answered Jan 28 '23 11:01

Michał Marczyk


If you use Emacs with CIDER as most Clojurians do, you already have a built-in debugger:

https://docs.cider.mx/cider/debugging/debugger.html

Chances are your favorite IDE/Editor has something built-in or a plugin already.

There is also (in no particular order):

  • spyscope
  • timbre/spy
  • tupelo/spyx
  • sayid
  • tools.trace
  • good old println

I would look at the above first. However there were/are other possibilities:

  • https://gist.github.com/ato/252421
  • https://github.com/philoskim/debux
  • https://github.com/pallet/ritz/tree/develop/nrepl-core
  • https://github.com/hozumi/eyewrap
  • probably many more

Also, if the function is simple enough you can add defs at development-time to peek inside the bindings at a given time inside your function.

like image 22
nha Avatar answered Jan 28 '23 09:01

nha