为什么REPL没有显示函数调用的完整跟踪?

我正在尝试通过《Common Lisp:符号计算的温和介绍》一书来学习 Common Lisp 。此外,我正在使用 SBCL、Emacs 和 Slime。

在第7章的进阶部分,作者建议使用trace功能。这无疑是一个非常有价值的工具。我很高兴看到它起作用了。

然而,显然,我的工具并不能完全像作者介绍的那样工作。

做如下定义后:

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

并在 REPL 上运行:

> (dtrace find-first-odd oddp)

他得到:

> (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

在我的环境中,使用相同的定义:

并进行跟踪(通过健全性检查):

CL-USER> (trace)
NIL
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

这看起来很尴尬,因为(trace)评估表明包含了奇数谓词。但是,在函数调用之后,它不会显示为跟踪操作。

在另一个示例中,我的两个函数都是由我定义的,并且不oddp涉及谓词等原语,它完美地工作:

(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

有没有办法解决这个问题?

回答

您可以调用trace多个函数,并且需要调用trace要查看其跟踪信息的每个函数。所以,你可以这样做:

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

但是,内置函数可能不会产生任何跟踪信息,并且oddp在 SBCL 中看起来是不可跟踪的。这可能是因为oddp在 SBCL 中内联了。您可以尝试使用notinline声明:

(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

如果失败,您可以将内置函数包装在另一个可以跟踪的函数定义中:

(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

您可能还想查看对 的调用find-if。在这里你可以看到,虽然find-if是一个内置函数,但在 SBCL 中它是可追溯的:

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


以上是为什么REPL没有显示函数调用的完整跟踪?的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>