普通lisp类型与非泛型运行时分析



我正在用普通lisp编写一个使用opengl的应用程序,随着事情的发展,我意识到我必须做出一些选择。我有一堆不同的类,它们都需要代码来快速而频繁地渲染它们,所以我正在考虑以下代码结构:

(defgeneric render (x))
(defmethod render ((x vanilla-foo))
   (generic-foo-stuff)
   (vanilla-specific-stuff)
   (more-generic-foo-stuff))
(defmethod render ((x chocolate-foo))
   (generic-foo-stuff)
   (chocolate-specific-stuff)
   (more-generic-foo-stuff))

等等,很多这样的方法。另一种选择是使用类型语句:

(defun render (any-old-foo)
   (generic-foo-stuff)
   (typecase
      (vanilla-foo 
         (vanilla-specific-stuff))
      (chocolate-foo
         (chocolate-specific-stuff))
      ;;and so on, lots of cases here
    )
    (more-generic-foo-stuff))

我认为这两种方式都很难看,但我的假设是lisp将在底层使用某种哈希表O(1)查找,将传递给泛型函数的参数类型映射到所需方法的位置,而第二个方法将需要O(n)种类型比较来完成typecase语句。另一方面,根据散列的快慢,我可能需要数千种不同的方法才能使第一种方法真正更快。

是否有好的性能理由让我更喜欢其中一个而不是另一个?我也愿意听取其他建议,或者参考一些文档,让我更清楚地了解每个案例的底层情况。我也很好奇你可能遇到过这种冲突的其他例子。

谢谢!

通过将泛型的东西分解到:before:after方法中,至少可以使使用泛型函数的代码不那么难看:

(defgeneric render (x))
(defmethod render :before (x) ; Do what always has to be done first
  (generic-foo-stuff))
(defmethod render :after (x) ;  Do what always has to be done last
  (more-generic-foo-stuff))
(defmethod render ((x vanilla-foo)) ; Do only vanilla-specific things here
   (vanilla-specific-stuff))
(defmethod render ((x chocolate-foo)) 
   (chocolate-specific-stuff))

可以使用泛型函数

  • 对于各种参数组合有多种实现
  • 想使函数可扩展
  • 希望通过重用片段(方法)来组装代码

那么我们不妨用:before:after方法重写你的例子。

如果代码应该尽可能快速和静态,那么泛型函数不是一个好的选择。

如果您需要提前计划性能,那么您最好做一些实验并测量时间。

最新更新