common-lisptraceslime

Why the REPL is not showing the full trace of the function call?


I am trying to learn Common Lisp with the book Common Lisp: A gentle introduction to Symbolic Computation. In addition, I am using SBCL, Emacs, and Slime.

In the advanced section of chapter 7, the author suggests the use of the trace function. This is definetly a really valuable tool. I was glad to see it working.

However, apparently, my tool does not work fully as the one presented by the author.

After doing the following definition:

(defun find-first-odd (x)
   (find-if #’oddp x))

And running on the REPL:

> (dtrace find-first-odd oddp)

He gets:

> (find-first-odd ’(2 4 6 7 8))
----Enter FIND-FIRST-ODD
| X = (2 4 6 7 8)
| ----Enter ODDP
| | NUMBER = 2
| \--ODDP returned NIL
| ----Enter ODDP
| | NUMBER = 4
| \--ODDP returned NIL
| ----Enter ODDP
| | NUMBER = 6
| \--ODDP returned NIL
| ----Enter ODDP
| | NUMBER = 7
| \--ODDP returned T
\--FIND-FIRST-ODD returned 7
7

On my environment, using the same definition:

(defun find-first-odd (x)
   (find-if #’oddp x))

And doing the trace (with a sanity check):

CL-USER> (trace)
NIL
CL-USER> (trace find-first-odd oddp)
(FIND-FIRST-ODD ODDP)

I get:

CL-USER> (find-first-odd '(2 4 6 7 8))
  0: (FIND-FIRST-ODD (2 4 6 7 8))
  0: FIND-FIRST-ODD returned 7

This seems awkward since the (trace) evaluation indicates the inclusion of the odd predicate. However, after the function call it does not appear as a traced operation.

In another example in which both of my functions were definied by me and no primitive such as oddp predicate were involved, it worked perfectly:

(defun half (n) (* n 0.5))

(defun average (x y)
  (+ (half x) (half y)))

CL-USER> (trace half average)
(HALF AVERAGE)

CL-USER> (average 3 7)
  0: (AVERAGE 3 7)
    1: (HALF 3)
    1: HALF returned 1.5
    1: (HALF 7)
    1: HALF returned 3.5
  0: AVERAGE returned 5.0
5.0

Is there a way to solve this?


Solution

  • You can call trace on multiple functions, and you need to call trace on each function for which you want to see trace information. So, you can do:

    CL-USER> (trace find-first-odd oddp)
    (FIND-FIRST-ODD ODDP)
    CL-USER> (find-first-odd '(2 4 6 7 8))
      0: (FIND-FIRST-ODD (2 4 6 7 8))
      0: FIND-FIRST-ODD returned 7
    7
    

    But, built-in functions may not produce any trace information, and it looks like oddp is not traceable in SBCL. This is probably because oddp is inlined in SBCL. You can try using the notinline declaration:

    (defun find-first-odd (x)
      (declare (notinline oddp))
      (find-if #'oddp x))
    
    CL-USER> (trace find-first-odd oddp)
    (FIND-FIRST-ODD ODDP)
    CL-USER> (find-first-odd '(2 4 6 7 8))
      0: (FIND-FIRST-ODD (2 4 6 7 8))
        1: (ODDP 2)
        1: ODDP returned NIL
        1: (ODDP 4)
        1: ODDP returned NIL
        1: (ODDP 6)
        1: ODDP returned NIL
        1: (ODDP 7)
        1: ODDP returned T
      0: FIND-FIRST-ODD returned 7
    7
    

    Failing that, you may wrap a built in function in another function definition which can be traced:

    (defun my-oddp (&rest args)
        (apply #'oddp args))
    
    (defun find-first-odd-trace (x)
      (find-if #'my-oddp x))
    
    CL-USER> (untrace)
    T
    CL-USER> (trace find-first-odd-trace my-oddp)
    (FIND-FIRST-ODD-TRACE MY-ODDP)
    CL-USER> (find-first-odd-trace '(2 4 6 7 8))
      0: (FIND-FIRST-ODD-TRACE (2 4 6 7 8))
        1: (MY-ODDP 2)
        1: MY-ODDP returned NIL
        1: (MY-ODDP 4)
        1: MY-ODDP returned NIL
        1: (MY-ODDP 6)
        1: MY-ODDP returned NIL
        1: (MY-ODDP 7)
        1: MY-ODDP returned T
      0: FIND-FIRST-ODD-TRACE returned 7
    7
    

    You might want to see the call to find-if, too. Here you can see that, while find-if is a built-in function, in SBCL it is traceable:

    CL-USER> (trace find-if)
    (FIND-IF)
    CL-USER> (find-first-odd-trace '(2 4 6 7 8))
      0: (FIND-FIRST-ODD-TRACE (2 4 6 7 8))
        1: (FIND-IF #<FUNCTION SB-IMPL::ENCAPSULATION {100307F6AB}> (2 4 6 7 8))
          2: (MY-ODDP 2)
          2: MY-ODDP returned NIL
          2: (MY-ODDP 4)
          2: MY-ODDP returned NIL
          2: (MY-ODDP 6)
          2: MY-ODDP returned NIL
          2: (MY-ODDP 7)
          2: MY-ODDP returned T
        1: FIND-IF returned 7
      0: FIND-FIRST-ODD-TRACE returned 7
    7