mys*_*eem 2 lisp sbcl common-lisp
我刚刚编写了一个subst在循环内调用的程序,以及许多其他函数,到目前为止,subst函数调用花费的时间最多。下面是包含我编写的程序精神的概念性代码片段。
(loop
with bindings = ((symbol1 . 1) (sybmol2 . 2) ... (sybmoln . n))
with x-copy
for x in xs
do
...
(setq x-copy (copy-cpd x))
(setf (cpd-identifiers1 x-copy) (subst-bindings bindings (cpd-identifiers1 x)))
(setf (cpd-identifiers2 x-copy) (subst-bindings bindings (cpd-identifiers2 x)))
...)
Run Code Online (Sandbox Code Playgroud)
subst-bindings对subst内部进行递归调用:
(defun subst-bindings (bindings generic)
(cond ((null bindings) generic)
(t (subst-bindings (cdr bindings)
(subst (cdar bindings) (caar bindings) generic)))))
Run Code Online (Sandbox Code Playgroud)
我在启用了统计分析器的情况下运行了我的实际代码,我得到了以下结果:
Self Total Cumul
Nr Count % Count % Count % Calls Function
------------------------------------------------------------------------
1 4585 45.8 6840 68.4 4585 45.8 - (LABELS SB-IMPL::S :IN SUBST)
2 2204 22.0 2205 22.1 6789 67.9 - EQL
3 489 4.9 489 4.9 7278 72.8 - SUBST
4 315 3.2 7537 75.4 7593 75.9 - SUBST-BINDINGS
5 150 1.5 235 2.3 7743 77.4 - PPRINT-DISPATCH
6 143 1.4 274 2.7 7886 78.9 - SB-IMPL::%FIND-SYMBOL
7 114 1.1 114 1.1 8000 80.0 - SB-IMPL::%MAKE-STRING-OUTPUT-STREAM
8 106 1.1 347 3.5 8106 81.1 - SB-KERNEL:OUTPUT-SYMBOL-NAME
9 94 0.9 113 1.1 8200 82.0 - SB-IMPL::STRING-SOUT
10 73 0.7 155 1.5 8273 82.7 - SB-KERNEL::VALUES-SPECIFIER-TYPE-R
11 70 0.7 70 0.7 8343 83.4 - SB-KERNEL:UB32-BASH-COPY
12 56 0.6 56 0.6 8399 84.0 - SB-KERNEL:%SXHASH-SIMPLE-SUBSTRING
13 51 0.5 51 0.5 8450 84.5 - MAKE-CPD
14 48 0.5 160 1.6 8498 85.0 - GET-OUTPUT-STREAM-STRING
15 48 0.5 48 0.5 8546 85.5 - WRITE-STRING
16 44 0.4 44 0.4 8590 85.9 - SB-KERNEL:%COERCE-CALLABLE-TO-FUN
17 43 0.4 741 7.4 8633 86.3 - PRINC
18 43 0.4 60 0.6 8676 86.8 - POSITION
19 39 0.4 151 1.5 8715 87.2 - SB-IMPL::%WRITE-STRING
20 39 0.4 46 0.5 8754 87.5 - SB-KERNEL:STRING=*
21 37 0.4 195 2.0 8791 87.9 - SB-KERNEL::SPECIFIER-TYPE-R
22 37 0.4 169 1.7 8828 88.3 - OPERATE-FACTOR
23 36 0.4 68 0.7 8864 88.6 - SB-VM::GENERIC-+
24 36 0.4 36 0.4 8900 89.0 - COPY-LIST
25 35 0.4 231 2.3 8935 89.4 - SB-KERNEL:SPECIFIER-TYPE
26 33 0.3 314 3.1 8968 89.7 - SB-INT:%INTERN
27 32 0.3 9146 91.5 9000 90.0 - CANDIDATE-NODES
28 31 0.3 31 0.3 9031 90.3 - SB-IMPL::SETUP-PRINTER-STATE
29 30 0.3 79 0.8 9061 90.6 - COPY-SEQ
30 30 0.3 45 0.4 9091 90.9 - GET-FULLY-QUALIFIED-CPD-VARS
31 30 0.3 30 0.3 9121 91.2 - SB-IMPL::OUTPUT-SYMBOL
32 28 0.3 1724 17.2 9149 91.5 - GENERATE-CPD-VARS
33 26 0.3 63 0.6 9175 91.8 - SB-INT:EQUAL-BUT-NO-CAR-RECURSION
34 25 0.3 25 0.3 9200 92.0 - SB-IMPL::VECTOR-SUBSEQ-DISPATCH/SIMPLE-VECTOR
35 24 0.2 24 0.2 9224 92.2 - (SB-IMPL::OPTIMIZED-DATA-VECTOR-REF T)
36 23 0.2 23 0.2 9247 92.5 - SB-KERNEL:HAIRY-DATA-VECTOR-REF/CHECK-BOUNDS
37 21 0.2 685 6.8 9268 92.7 - (LABELS SB-IMPL::HANDLE-IT :IN SB-KERNEL:OUTPUT-OBJECT)
38 20 0.2 70 0.7 9288 92.9 - SB-IMPL::COMPUTE-SYMBOL-HASH
39 19 0.2 1295 12.9 9307 93.1 - COMBINE-SYMBOLS
40 19 0.2 395 4.0 9326 93.3 - INTERN
41 19 0.2 104 1.0 9345 93.5 - (FLET SB-IMPL::REPLACE-ALL :IN GET-OUTPUT-STREAM-STRING)
42 19 0.2 19 0.2 9364 93.6 - SB-C:RETURN-MULTIPLE
43 19 0.2 19 0.2 9383 93.8 - SB-KERNEL:VECTOR-SUBSEQ*
44 18 0.2 133 1.3 9401 94.0 - COPY-CPD
Run Code Online (Sandbox Code Playgroud)
SBCL 用户手册描述了如何解释此表:
对于每个函数,该表将显示三个绝对和相对样本计数。Self 列显示在直接执行该函数时采集的样本。Total 列显示在执行该函数或从其调用的函数时采集的样本(采样到特定于平台的深度)。Cumul 列显示所有 Self 列的总和,包括表中的该行。
如您所见,前三个条目中的两个是 subst 相关函数,并且在这些函数期间采集的样本百分比不成比例地高于其余函数调用。这让我想知道,是subst在 sbcl 中以有效的方式实现的吗?如果没有,是否有任何更有效的替代方法可以用来执行替换?
谢谢你的帮助
查看标准函数sublis和nsublis. 他们使用关联列表进行替换。
CL-USER > (sublis '((x . 10) (y . 20))
'(* x (+ x y) (* y y)))
(* 10 (+ 10 20) (* 20 20))
Run Code Online (Sandbox Code Playgroud)
风格:
我不会以递归方式编写替换函数。
(defun subst-bindings (bindings generic)
(loop for (b v) in bindings
do (setf generic (subst v b generic)))
generic)
Run Code Online (Sandbox Code Playgroud)
以上确保它实际上是一个循环,并且在这种情况下,解构使代码更短,便于阅读。在可移植的 Common Lisp 中,尾递归函数并不总是转换为有效的循环。