我正在尝试编写一个(高阶函数),该函数接受一个向量和一个函数,并对该函数进行二进制搜索,即,如果返回-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,但从未使用过。怎么了?
答案 0 :(得分:5)
(defun bin-search (ls fpred)
请使用有意义的名称,您有许多短名称或缩写,很难读懂。例如,ls
让我想到了一个列表,该列表可以简单地命名为list
,但是显然您正在使用向量,所以也许vec
或vector
?>
(let ((l (length ls))
(x (aref ls (floor (length ls) 2))))
如果要重用在同一遍中定义的长度l
,则可以改用let*
,并写成l
而不是第二次出现的(length ls)
(labels (binsearch (ls fpred l m)
标签的语法是绑定(name (<args>) <body>)
的列表,因此您需要添加另一对括号,例如(labels ((binsearch (<args>) <body>)) ...
此外,您不需要传递fpred
作为参数,它不会从binsearch
的一次调用更改为另一次调用。您只需从本地函数内部引用bin-search
的{{1}}参数即可。
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
答案 1 :(得分:1)
修复(据说)所有问题,现在可以工作了。非常感谢。
(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