Lisp中C结构的惯用等价物是什么?

时间:2010-12-28 12:43:13

标签: c struct lisp common-lisp

在C类语言中,从一开始就在每本入门书中都强调结构/记录和对象。然后,他们的完整系统是围绕管理这些结构,它们的相互关系和继承而设计的。

在Lisp文档中,你通常可以找到1-2页关于Lisp“也”如何有一个defstruct,一个简单的例子,通常就是这样。此外,根本没有提到结构的嵌套。

对于来自C背景的人来说,首先看来,分层组织不同的数据类型不是Lisp中的首选方法,但除了CLOS之外,CLOS是一个完整的对象系统,如果你只是想要结构,那就太复杂了从将所有东西都放到列表中,没有一种明显的方法来转移你的C结构知识。

最像C结构的分层组织数据的惯用Lisp方法是什么?

-

我认为对我的问题的总结回答是:对于初学者学习目的,可以使用defstruct和/或plists,虽然“遗留特征”,因为它们最接近C结构,但它们已被大大取代通过更灵活的defclass / CLOS,这是大多数Lisp程序今天使用的。

这是我关于SO的第一个问题,所以感谢大家的回答。

6 个答案:

答案 0 :(得分:22)

使用CLOS。这并不复杂。

否则使用结构。

如果您有特定的问题如何使用它们,那么请问。

(defclass point ()
  ((x :type number)
   (y :type number)))

(defclass rectangle ()
  ((p1    :type point)
   (p2    :type point)
   (color :type color)))

这样的东西最终会导致像Rectangles in CLIM这样的接口(Common Lisp Interface Manager)。

<强>记录

稍微扩展一下:历史上“结构”已经在某些低级情况下使用过。结构具有单一继承,并且插槽访问“快速”。一些Lisp方言比Common Lisp提供的结构更多。然后从70年代中期开始,为Lisp开发了各种形式的面向对象的表示。大多数结构化对象的表示从结构转移到某种面向对象的Lisp扩展。在80年代流行的是基于类的系统,如Flavors,LOOPS等。基于帧或基于原型的系统(如KEE Units或Object Lisp)也很受欢迎。第一个Macintosh Common Lisp为其所有UI和IO工具使用了Object Lisp。麻省理工学院的Lisp机器基本上到处都使用Flavors。从80年代中期开始,ANSI CL就开发出来了。常见的OO系统是专为Common Lisp:CLOS开发的。它基于Flavors和Loops。在那段时间里,除了实现者找到改进实现的方法并提供浅层CLOS集成之外,大部分时间都没有做真正改进的结构。例如,结构不提供任何数据包。如果有两个4位内容的插槽,则无法指示Common Lisp将两个插槽编码为单个8位内存区域。

作为一个例子,您可以在Lisp Machine Manual, chapter on structures (PDF)中看到它的结构比Common Lisp提供的结构复杂得多。其中一些已经出现在70年代的Maclisp中:DEFSTRUCT in the Maclisp manual

CLOS,Common Lisp对象系统

大多数人都同意CLOS是一个不错的设计。它有时会导致“更大”的代码,主要是因为标识符可能会变长。但是有一些CLOS代码,就像AMOP书中的代码一样,编写得非常好,并展示了它应该如何使用。

随着时间的推移,实现者必须应对开发人员想要使用CLOS的挑战,但也希望拥有结构的“速度”。对于“完整”CLOS来说,这更是一项任务,其中包括CLOS几乎标准的元对象协议(MOP)。所以实现者提供了一些技巧。在80年代,一些软件使用了一个开关,所以它可以使用结构编译或使用CLOS-CLX(低级Common Lisp X11接口就是一个例子)。原因是:在某些计算机和实现上,CLOS比结构慢得多。今天提供这样的编译开关是不常见的。

如果我今天看一个很好的Common Lisp实现,我希望它几乎可以在任何地方使用CLOS。 STREAM是CLOS类。条件是CLOS类。 GUI工具包使用CLOS类。编辑器使用CLOS。它甚至可能将外来类(比如,Objective C类)集成到CLOS中。

在任何非玩具Common Lisp实现中,CLOS将成为提供结构化数据,通用行为和其他一些东西的工具。

正如其他一些答案所述,在某些地方可能不需要CLOS。

Common Lisp可以从函数中返回多个值:

(defun calculate-coordinates (ship)
   (move-forward ship)
   (values (ship-x ship)
           (ship-y ship)))

可以将数据存储在闭包中:

(defun create-distance-function (ship x y)
   (lambda ()
     (point-distance (ship-x ship) (ship-y ship) x y)))

对于配置,可以使用某种列表:

(defship ms-germany :initial-x 0 :initial-y 0)

你可以打赌我会在CLOS中实施船模型。

编写和维护CLOS软件的一个教训是,它需要经过精心设计,CLOS非常强大,人们可以使用它创建非常复杂的软件 - 这种复杂性往往不是一个好主意。重构和简化!幸运的是,对于许多任务来说,基本的CLOS设施就足够了:DEFCLASS,DEFMETHOD和MAKE-INSTANCE。

指向CLOS介绍的指针

首先,Richard P. Gabriel有CLOS papers下载。

另见:

答案 1 :(得分:5)

答案 2 :(得分:4)

defstruct的示例简短而简单,因为没有太多可说的内容。 C struct很复杂:

  • 内存管理
  • 由于联合,内联嵌套结构导致的内存布局复杂 在C中,structs也用于其他目的:

  • 访问内存

  • 由于缺乏多态性或传递'any'类型值的能力:传递void*
  • 是惯用的
  • 由于无法通过其他方式传递数据;例如,在Lisp中,您可以传递一个具有所需数据的闭包
  • 由于缺乏高级通话惯例;一些函数在结构
  • 中接受它们的参数

在Common Lisp中,defstruct大致相当于Java的/ C#的class:单个继承,固定的槽,可以用作defmethod中的说明符(类似于virtual } 方法)。结构完全可用于嵌套数据结构。

Lisp程序倾向于不使用深层嵌套结构(Lisp的源代码是主要的例外),因为通常可以使用更简单的表示。

答案 3 :(得分:2)

我认为C结构的惯用等价物不需要首先将数据存储在结构中。我说至少50%的C风格代码我已经移植到Lisp,而不是将数据存储在一些精心设计的结构中,我只计算我想要计算的内容。 C需要结构来临时存储所有内容,因为它的表达式非常弱。

如果你是一些C风格代码的具体例子,我相信我们可以证明一种在Lisp中实现它的惯用方法。

除此之外,请记住Lisp的s-exps 分层数据。例如,Lisp中的if表达式本身就是分层数据。

答案 4 :(得分:2)

(defclass point ()
          ( x y z))

(defun distance-from-origin (point)
               (with-slots (x y z)
                   point
                 (sqrt (+ (* x x) (* y y) (* z z)))))

我认为这是我想要的,可以在这里找到:

http://cl-cookbook.sourceforge.net/clos-tutorial/index.html ÿ

答案 5 :(得分:0)

为什么不使用哈希表?结构中的每个成员都可以是哈希表中的键。