具有更高级别功能的lisp中的二进制搜索

And*_* S. 1 lisp common-lisp binary-search

我正在尝试编写一个(更高阶函数),它接受一个向量和一个函数,并根据该函数进行二进制搜索,即如果它返回-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))))
Run Code Online (Sandbox Code Playgroud)

编译器说变量FPRED已定义但从未使用过.怎么了?

cor*_*ump 5

(defun bin-search (ls fpred)
Run Code Online (Sandbox Code Playgroud)

请使用有意义的名称,您有许多短名称或缩写,难以阅读.例如,ls让我想到一个列表,可以简单地命名list,但显然你正在使用向量,所以也许vecvector

 (let ((l (length ls))
       (x (aref ls (floor (length ls) 2))))
Run Code Online (Sandbox Code Playgroud)

如果要重用l同一个let中定义的长度,可以使用a let*代替,而l不是第二次出现(length ls).

       (labels (binsearch (ls fpred l m)
Run Code Online (Sandbox Code Playgroud)

标签的语法是绑定列表(name (<args>) <body>),因此您需要添加另一对括号,例如(labels ((binsearch (<args>) <body>)) ...

另外,您不需要fpred作为参数传递,它不会从一次调用更改binsearch为另一次.您可以直接参考bin-searchfpred参数从本地函数中.

                (case (funcall #'fpred (aref ls m))
Run Code Online (Sandbox Code Playgroud)

当你在函数命名空间中编写时#'fpred,(function fpred)你正在寻找它.在这里,您希望访问与命名变量关联的函数,因此您可以删除该部分.fpredfpred#'

                 (-1 (binsearch (ls fpred l (floor (- m l) 2))))
Run Code Online (Sandbox Code Playgroud)

当你写(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))))
Run Code Online (Sandbox Code Playgroud)