为什么 REPL 没有显示函数调用的完整轨迹?
Why the REPL is not showing the full trace of the function call?
我正在尝试通过 Common Lisp:对符号计算的简单介绍 来学习 Common Lisp。此外,我正在使用 SBCL、Emacs 和 Slime。
在第7章进阶部分,作者建议使用trace函数。这绝对是一个非常有价值的工具。我很高兴看到它起作用了。
但是,显然,我的工具无法像作者提供的那样完全工作。
进行如下定义后:
(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
在我的环境中,使用相同的定义:
(defun find-first-odd (x)
(find-if #’oddp x))
并进行跟踪(通过完整性检查):
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
我正在尝试通过 Common Lisp:对符号计算的简单介绍 来学习 Common Lisp。此外,我正在使用 SBCL、Emacs 和 Slime。
在第7章进阶部分,作者建议使用trace函数。这绝对是一个非常有价值的工具。我很高兴看到它起作用了。
但是,显然,我的工具无法像作者提供的那样完全工作。
进行如下定义后:
(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
在我的环境中,使用相同的定义:
(defun find-first-odd (x)
(find-if #’oddp x))
并进行跟踪(通过完整性检查):
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