在C类语言中,从一开始就在每本入门书中都强调结构/记录和对象。然后,他们的完整系统是围绕管理这些结构,它们的相互关系和继承而设计的。
在Lisp文档中,你通常可以找到1-2页关于Lisp“也”如何有一个defstruct,一个简单的例子,通常就是这样。此外,根本没有提到结构的嵌套。
对于来自C背景的人来说,首先看来,分层组织不同的数据类型不是Lisp中的首选方法,但除了CLOS之外,CLOS是一个完整的对象系统,如果你只是想要结构,那就太复杂了从将所有东西都放到列表中,没有一种明显的方法来转移你的C结构知识。
最像C结构的分层组织数据的惯用Lisp方法是什么?
-
我认为对我的问题的总结回答是:对于初学者学习目的,可以使用defstruct和/或plists,虽然“遗留特征”,因为它们最接近C结构,但它们已被大大取代通过更灵活的defclass / CLOS,这是大多数Lisp程序今天使用的。
这是我关于SO的第一个问题,所以感谢大家的回答。
答案 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
也用于其他目的:
访问内存
void*
在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)
为什么不使用哈希表?结构中的每个成员都可以是哈希表中的键。