Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ajax/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Optimization 使用类型声明进行优化的常见Lisp最佳实践_Optimization_Common Lisp_Compiler Optimization - Fatal编程技术网

Optimization 使用类型声明进行优化的常见Lisp最佳实践

Optimization 使用类型声明进行优化的常见Lisp最佳实践,optimization,common-lisp,compiler-optimization,Optimization,Common Lisp,Compiler Optimization,我有一个公共Lisp函数,它合并了两个有序的符号列表,没有重复项(两个有序集): 或者,如我所想,如果还需要在我的代码中添加说明符?但是,我应该在哪里以及在什么情况下添加它 有一些规则可以遵循吗 出于优化目的,我是否也应该声明函数的类型?风格 由于您实际上没有以任何有用的方式使用扩展的循环功能,而且循环语法对于您的示例来说也不是很好,因此我建议使用原语循环编写它。请参见COND如何使Lisp程序员更易于阅读: (defun my-merge (x y &aux (first (list

我有一个公共Lisp函数,它合并了两个有序的符号列表,没有重复项(两个有序集):

或者,如我所想,如果还需要在我的代码中添加
说明符
?但是,我应该在哪里以及在什么情况下添加它

有一些规则可以遵循吗

出于优化目的,我是否也应该声明函数的类型?

风格

由于您实际上没有以任何有用的方式使用扩展的
循环
功能,而且
循环
语法对于您的示例来说也不是很好,因此我建议使用原语
循环
编写它。请参见
COND
如何使Lisp程序员更易于阅读:

(defun my-merge (x y &aux (first (list nil)) (last first) cx cy)
  (macrolet ((cdr! (v)
               `(setf ,v (cdr ,v))))
    (loop (unless (and x y)
            (return))
          (setf cx (car x) cy (car y))
          (cond ((string= cx cy)
                 (cdr! x))
                ((string< cx cy)
                 (rplacd last (list cx))
                 (cdr! last)
                 (cdr! x))
                (t
                 (rplacd last (list cy))
                 (cdr! last)
                 (cdr! y))))
    (rplacd last (or x y))
    (cdr first)))
请注意,了解参数类型可能还不够,可能需要声明结果的类型。因此,
的使用就是
<代码>反汇编和分析器是您的朋友

  • basic=编译器需要类型声明、优化,但也可以推断某些类型。标准语言的类型是已知的
甚至更好的编译器也会抱怨类型错误,可以跨函数传播类型,并且在某些优化不可能时会抱怨

序列函数

请注意,序列函数是一种特殊的困难情况。序列具有子类型列表和向量(包括字符串)

假设序列函数是:

(foo result-type sequence-1 sequence-2 fn)
  • 如果序列是同一类型的,那么可能需要为列表和向量提供一个优化的代码版本

  • 如果序列的类型不同,将一个序列转换为不同的类型可能会很有用。也许不是

  • 结果类型也有影响,根据结果类型,可能/必要使用不同的算法

所以自由度相当高。编译器可能有助于快速编写代码。但是,特定序列函数的实现也可以在运行时进行一些优化

然后,
fn
是一个接受元素并生成新元素的函数。了解它的类型签名可能会有所帮助——或者不知道

我真的说不出当前哪个通用Lisp具有复杂的序列函数实现。尽管我记得符号学和常见的Lisp实现在这方面做了一些努力

文件和论文

通常,编译器可以优化什么以及如何优化都没有很好的文档记录(如果有的话)。有一些关于这个主题的论文,但它们往往是旧的和/或过时的

  • CMUCL的Python编译器:
  • CMUCL的Python编译器:
  • (附言)
  • 快板CL:
  • LispWorks:

优化、使用类型声明进行优化和类型推断完全是特定于实现的。您将在实现中找到一切:从基于类型声明的零优化、类型声明的使用,甚至类型推断(这意味着需要更少的类型声明)。通常:声明类型并进行优化,然后查看生成的汇编程序和/或度量时间。如果您使用SBCL、CMUCL或LispWorks,编译器将(或可以配置为)告诉您无法优化的位置和原因。然后添加必要的声明。推出自己的解决方案总是很有趣的,但请注意,最好的选择之一可能就是使用标准函数。它可以生成任意的序列类型,使用任意的谓词,等等,而且实现可能已经对其进行了优化(可能值得查看它们的源代码)。这是语言发展过程中令人沮丧的一个方面,因为它最初被封锁了。@renzo,我们会的,这是一个很好的理由,让我们来看看你自己的!很多时候,优化问题甚至没有考虑标准库函数。由于Co合并了不同类型的输入和输出,因此它的效率可能低于专门的版本。关于测试,我想说的是,一定要尝试降低安全性,而不仅仅是添加类型声明。类型告诉编译器它还可以检查一件事,安全性告诉它它不必检查。我想你已经考虑过其他数据结构来解决你的问题了?您提到列表很大,对于大量数据,列表通常不是最优的。不知道你在做什么很难说,但是预先分配空间的阵列可能会更快。非常好的答案,非常感谢你的代码,以及解释和所有链接!精神食粮。
(defun my-merge (x y &aux (first (list nil)) (last first) cx cy)
  (macrolet ((cdr! (v)
               `(setf ,v (cdr ,v))))
    (loop (unless (and x y)
            (return))
          (setf cx (car x) cy (car y))
          (cond ((string= cx cy)
                 (cdr! x))
                ((string< cx cy)
                 (rplacd last (list cx))
                 (cdr! last)
                 (cdr! x))
                (t
                 (rplacd last (list cy))
                 (cdr! last)
                 (cdr! y))))
    (rplacd last (or x y))
    (cdr first)))
(let ((a 1) (b 2))
  (declare (integer a b))
  (let ((c (the integer (* (the integer (+ a b))
                           (the integer (- a b))))))
     (declare (integer c))
     (the integer (* c c))))
(foo result-type sequence-1 sequence-2 fn)