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

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

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

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

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

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

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

使用CLOS。 这并不复杂。

否则使用结构。

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

(defclass point () ((x :type number) (y :type number))) (defclass rectangle () ((p1 :type point) (p2 :type point) (color :type color))) 

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

历史

稍微扩展一下:历史上“结构”已经在一些低级情况下使用。 结构具有单一inheritance,并且插槽访问“快速”。 一些Lisp方言比Common Lisp提供的结构更多。 然后从70年代中期开始,为Lisp开发了各种forms的面向对象的表示。 大多数结构化对象的表示从结构转移到某种面向对象的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机器手册中看到结构章节(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))) 

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

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

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

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

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

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

CLOS介绍的指针

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

另见:

  • http://cl-cookbook.sourceforge.net/clos-tutorial/index.html
  • http://www.aiai.ed.ac.uk/~jeff/clos-guide.html
  • 从Practical Common Lisp, Object Reorientation,Classes预订章节
  • 从Practical Common Lisp, Object Reorientation,Generic Functions预订章节
  • C ++ Coder的Lisp风格OO新手指南
  • 书: 元对象协议的艺术 。 根据一个名叫Alan Kay的人,十年来最重要的计算机科学着作,不幸的是为Lispers写的;-)。 该书解释了如何修改或扩展CLOS本身。 它还包括一个简单的CLOS实现作为源。 对于普通用户来说,这本书并不是真的需要,但编程风格是真正的Lisp专家。

物业清单(plists)

defstruct例子简短而简单,因为对它们没什么好说的。 C的struct很复杂:

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

  • 访问内存

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

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

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

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

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

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

 (defclass point () ( xyz)) (defun distance-from-origin (point) (with-slots (xyz) point (sqrt (+ (* xx) (* yy) (* zz))))) 

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

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

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