Common Lisp:专门针对数组长度的通用函数 [英] Common Lisp: Generic Function Specializing on Array Length
问题描述
我刚刚开始使用泛型函数,并且想知道这是否可行(我真的希望如此!).
I am just getting started with generic functions and am wondering if this is possible (I really hope so!).
我已经制作了3个用于处理不同长度向量的软件包: vector2,vector3 和 vector4 .
I have made 3 packages for handling vectors of different lengths: vector2, vector3 and vector4.
每个程序包都有处理该长度向量的函数:
Each package has functions that handle vectors of that length:
vector2:normalize - for normalizing *vector2s*
vector3:normalize - for normalizing *vector3s*
etc.
我的向量是类型化数组(为了速度和内存的使用,因为这是为了编写游戏),所以 vector3 是:
My vectors are typed arrays (for speed and memory use as this is for writing games) so a vector3 is:
(make-array 3 :element-type `single-float).
现在,我正在编写一个名为 vectors 的程序包,其中将包含处理任何矢量类型的通用函数.
Now I am writing a package called vectors which will contain generic functions to handle any vector types.
因此,传递向量:将 vector3 归一化应该返回 vector3 ,依此类推.
So passing vector:normalize a vector3 should return a vector3 and so on.
我尝试过:
(defmethod v+1 ((vec-a #.(class-of (make-array 3
:element-type
`single-float)))
(vec-b #.(class-of (make-array 3
:element-type
`single-float))))
(v3:v+1 vec-a vec-b))
(defmethod v+1 ((vec-a #.(class-of (make-array 4
:element-type
`single-float)))
(vec-b #.(class-of (make-array 4
:element-type
`single-float))))
(v4:v+1 vec-a vec-b))
...based on what I saw in question 6083238, but obviously that only specialized on simple, single-float arrays as:
V> (class-of (make-array 4 :element-type `single-float))
#<BUILT-IN-CLASS SB-KERNEL::SIMPLE-ARRAY-SINGLE-FLOAT>
考虑到它需要快速而不是占用内存的情况,最好的方法是什么?
What would be the best method of doing this, considering it needs to be fast and not memory hogging?
提前加油!
推荐答案
CL中的泛型函数可以通过类或EQL-specializer进行专门化(请参见
Generic functions in CL can be specialized either with classes or EQL-specializer (see PCL chapter on GFs). Classes aren't types, although there's some relation. But in your case you have a single class and a single type. So, effectively, you want to specialize the methods on some arbitrary property. This can only be achieved with an EQL-specializer:
(defmethod v+1 ((size (eql 3)) vec-a vec-b)
(v3:v+1 vec-a vec-b))
(defmethod v+1 ((size (eql 4)) vec-a vec-b)
(v4:v+1 vec-a vec-b))
他们不做任何边界检查,而且也比较笨拙.第一个问题可以通过在方法的主体内部添加检查来解决:
They don't do any bounds checking, and also are somewhat more clumsy. The first problem can be solved by adding a check inside the method's body:
(defmethod v+1 ((size (eql 3)) vec-a vec-b)
(assert (= 3 (length vec-a) (length vec-b))
"Vector size mismtach")
(v3:v+1 vec-a vec-b))
您还可以定义一个宏以生成任何大小的此类方法.
You can also define a macro to generate such methods for any size.
另一种选择是在呼叫站点使用宏,这将提供一个更简单的界面并可以执行错误检查:
Another option is to use a macro at call site, that will present a simpler interface and can perform error checking as well:
(defmacro v+1* (vec-a vec-b)
(once-only (vec-a vec-b)
`(if (= (length ,vec-a) (length ,vec-b))
(v+1 (length ,vec-a) ,vec-a ,vec-b)
(error "Vector size mismatch"))))
有关ONCE-ONLY
的讨论,请参见有关宏的PCL章节.
这篇关于Common Lisp:专门针对数组长度的通用函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!