我正在尝试编写一个(高阶函数(,它接受一个向量和一个函数,并根据该函数进行二叉搜索,即如果它返回 -1,我们需要更低,对于 1 - 更高,对于 0,我们找到了正确的位置。 我想出了这样的东西,但似乎我在传递函数作为参数时做错了:
(defun bin-search (ls fpred)
(let ((l (length ls))
(x (aref ls (floor (length ls) 2))))
(labels (binsearch (ls fpred l m)
(case (funcall #'fpred (aref ls m))
(-1 (binsearch (ls fpred l (floor (- m l) 2))))
(0 (return-from binsearch m))
(1 (binsearch (ls fpred m (+ m (floor (- m l) 2)))))))
(binsearch ls fpred 0 l))))
编译器说变量FPRED被定义但从未使用过。怎么了?
(defun bin-search (ls fpred)
请使用有意义的名称,您有很多短名称或缩写,很难阅读。例如,ls
让我想到了一个列表,可以简单地命名为list
,但显然您正在使用向量,所以也许vec
或vector
?
(let ((l (length ls))
(x (aref ls (floor (length ls) 2))))
如果要重用同一 let 中定义的长度l
,可以改用let*
,并写入l
而不是第二次出现(length ls)
。
(labels (binsearch (ls fpred l m)
标签的语法是绑定(name (<args>) <body>)
的列表,因此您需要添加另一对括号,例如(labels ((binsearch (<args>) <body>)) ...
此外,您不需要将fpred
作为参数传递,它不会从binsearch
的一个调用更改为另一个调用。你可以从本地函数内部引用bin-search
的fpred
参数。
(case (funcall #'fpred (aref ls m))
当你写#'fpred
时,相当于(function fpred)
,你在函数命名空间中寻找fpred
。在这里,您要访问与名为fpred
的变量关联的函数,因此您可以删除#'
部分。
(-1 (binsearch (ls fpred l (floor (- m l) 2))))
当你写(binsearch (ls fpred ...))
时,这意味着:用一个值调用binsearch
,通过调用函数ls
参数获得fpred
, ....括号很重要,您需要在此处删除它们。
(0 (return-from binsearch m))
(1 (binsearch (ls fpred m (+ m (floor (- m l) 2)))))))
(binsearch ls fpred 0 l))))
修复(据说(所有内容,它现在可以工作了。多谢。
(defun bin-search (vec fpred)
(let* ((l (length vec)))
(labels ((binsearch (vec l m)
(case (funcall fpred (aref vec m))
(-1 (binsearch vec l (+ l (floor (- m l) 2))))
(0 (return-from binsearch m))
(1 (binsearch vec m (+ m (floor (- m l) 2)))))))
(binsearch vec 0 (floor l 2)))))
改进:
let
而不是let*
- 内部函数的名称已更改
- 不需要
return-from
应用的:
(defun bin-search (vec fpred)
(let ((l (length vec)))
(labels ((bin-search-aux (vec l m)
(case (funcall fpred (aref vec m))
(-1 (bin-search-aux vec l (+ l (floor (- m l) 2))))
( 0 m)
( 1 (bin-search-aux vec m (+ m (floor (- m l) 2)))))))
(bin-search-aux vec 0 (floor l 2)))))
let
替换为&aux
arg -> 减少一个缩进级别vec
不需要传递
应用的:
(defun bin-search (vec fpred &aux (l (length vec)))
(labels ((bin-search-aux (l m)
(case (funcall fpred (aref vec m))
(-1 (bin-search-aux l (+ l (floor (- m l) 2))))
( 0 m)
( 1 (bin-search-aux m (+ m (floor (- m l) 2)))))))
(bin-search-aux 0 (floor l 2)))))
测试:
CL-USER > (bin-search #(1 2 3 4 5 6 7 8 9)
(lambda (x)
(if (< x 7) 1 (if (> x 7) -1 0))))
6