用通用函数替换普通函数

Replacing an ordinary function with a generic function

我想将 elt、nth 和 mapcar 等名称用于我正在制作原型的新数据结构,但这些名称指定普通函数,因此我认为需要将其重新定义为通用函数。

大概是重新定义这些名称的形式不好?

有没有办法告诉 defgeneric 不要生成程序错误并继续替换函数绑定?

这些不是通用函数或只是历史性函数是否有充分的理由?

请问这里的智慧和最佳实践是什么?

如果您使用的是 SBCL 或 ABCL,并且不关心 ANSI 合规性,则可以研究可扩展序列:

http://www.sbcl.org/manual/#Extensible-Sequences

http://www.doc.gold.ac.uk/~mas01cr/papers/ilc2007/sequences-20070301.pdf

...您不能在 COMMON-LISP 包中重新定义函数,但您可以创建一个新包并隐藏要重新定义的函数的导入。

Is there a good reason for these not being generic functions or is just historic?

Common Lisp 在它的某些领域有一些语言层次。软件的较高级别部分可能需要构建在较低级别的结构上。

它的目标之一是足够快以适应一系列应用程序。

Common Lisp 还引入了 sequences 的概念,这是对列表和向量的抽象,当时该语言还没有对象系统。 CLOS 在最初的 Common Lisp 设计之后出现了几年。

举个例子,比如平等 - 对于数字。

Lisp 有 =:

(= a b)

这是比较数字的最快方法。 = 也仅为数字定义。

然后是eqlequalequalp。这些适用于数字,但也适用于其他一些数据类型。

现在,如果您需要更快的速度,您可以声明类型并告诉编译器生成更快的代码:

(locally
  (declare (fixnum a b)
           (optimize (speed 3) (safety 0)))
  (= a b))

那么,为什么 = 不是 CLOS 通用函数?

a) 它是在 CLOS 不存在时引入的

但同样重要:

b) 在 Common Lisp 中,不知道(现在仍然不知道)如何使 CLOS 通用函数 = 与典型使用场景的非通用函数一样快 - 同时保留动态类型和可扩展性

CLOS 泛型函数只是有速度损失。运行时调度成本。

CLOS 最适用于更高级别的代码,然后真正受益于可扩展性、多调度等功能,inheritance/combinations。通用函数应该用于定义的通用行为——而不是类似方法的集合。

有了更好的实现技术、特定于实现的语言增强等,可能会增加可以使用 CLOS 以高性能方式编写的代码范围。这已经用 Dylan 和 Julia 等编程语言进行了尝试。

Presumably it's bad form to redefine these names?

Common Lisp 实现不允许您就这样替换它们。请注意,您的替换功能应该以与旧功能一致的方式实现。此外,可以以某种方式内联旧版本,而不是在任何地方都可以替换。

Is there a way to tell defgeneric not to generate a program error and to go ahead and replace the function binding?

您需要在更换时确保更换件正常工作。替换函数的代码,可能会使用您正在替换的那些函数。

仍然,实现允许您替换 CL 函数 - 但这是特定于实现的。例如 LispWorks 提供变量 lispworks:*packages-for-warn-on-redefinition*lispworks:*handle-warn-on-redefinition*。可以绑定它们或全局更改它们。

What's the considered wisdom and best practice here please?

有两种方法:

  • 使用特定于实现的方式来替换标准的 Common Lisp 函数

这可能很危险。另外,您需要为要使用的所有 CL 实现支持它...

  • 使用语言包,您可以在其中定义新语言。在这里,这将是标准的 Common Lisp 加上你的 extensions/changes。导出用户将使用的所有内容。在您的软件中使用此包而不是 CL.