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

muu*_*gnu 20 c lisp struct common-lisp

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

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

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

什么是层次组织数据的惯用Lisp方法,最类似于C结构?

-

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

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

Rai*_*wig 22

使用CLOS.这并不复杂.

否则使用结构.

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

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

(defclass rectangle ()
  ((p1    :type point)
   (p2    :type point)
   (color :type color)))
Run Code Online (Sandbox Code Playgroud)

这样的东西最终会导致像CLIM中的矩形这样的接口(Common Lisp Interface Manager).

历史

稍微扩展一下:历史上,"结构"已被用于某些低级别的情况.结构具有单一继承,并且插槽访问"快速".一些Lisp方言比Common Lisp提供的结构更多.然后从70年代中期开始,为Lisp开发了各种形式的面向对象的表示.大多数结构化对象的表示从结构转移到某种面向对象的Lisp扩展.在80年代流行的是基于类的系统,如Flavors,LOOPS等.基于帧或基于原型的系统(如KEE单元或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机器手册的结构章节(PDF)中看到它的结构比Common Lisp提供的结构复杂得多.其中一些已经出现在70年代的Maclisp中:Maclisp手册中的DEFSTRUCT.

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)))
Run Code Online (Sandbox Code Playgroud)

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

(defun create-distance-function (ship x y)
   (lambda ()
     (point-distance (ship-x ship) (ship-y ship) x y)))
Run Code Online (Sandbox Code Playgroud)

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

(defship ms-germany :initial-x 0 :initial-y 0)
Run Code Online (Sandbox Code Playgroud)

你可以打赌我会在CLOS中实现船模型.

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

CLOS介绍的指针

首先,Richard P. Gabriel有他的CLOS论文供下载.

另见:

  • @ muuh-gnu不要使用plist.结构是一项遗留功能.大多数软件都会将CLOS类用于结构化数据.如果CLOS以及如何使用它,甚至还有书籍解释基础知识.在那个级别上它并不比C中的结构更难.实际上它更简单,因为Common Lisp缺乏数据布局的特征. (6认同)

dmi*_*_vk 5

的例子defstruct简短而简单,因为没有什么可说的。Cstruct很复杂:

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

  • 访问内存

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

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

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