Common Lisp:专门针对数组长度的通用函数 [英] Common Lisp: Generic Function Specializing on Array Length

查看:75
本文介绍了Common Lisp:专门针对数组长度的通用函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我刚刚开始使用泛型函数,并且想知道这是否可行(我真的希望如此!).

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆