简体   繁体   English

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

[英]What's the idiomatic equivalent of C structs in Lisp?

In C-type languages, there is a strong emphasis on structs/records and objects from the very beginning and in every introductory book.在 C 类型语言中,从一开始和每本介绍性书籍都非常强调结构/记录和对象。 Then, their complete systems are designed around managing such structs, their mutual relations and inheritance.然后,他们的完整系统是围绕管理这些结构、它们的相互关系和继承而设计的。

In Lisp documentation, you can usually find 1-2 pages about how Lisp "also" has a defstruct, a simple example, and thats usually it.在 Lisp 文档中,你通常可以找到 1-2 页关于 Lisp 如何“也”有一个 defstruct,一个简单的例子,通常就是这样。 Also, nesting of structures is never mentioned at all.此外,根本没有提到结构的嵌套。

For someone coming from a C background, it first seems that organizing different data types hierarchically isnt the preferred method in Lisp, but apart from CLOS, which is a full blown object system and too complicated if you just want structs, and apart from craming everything into lists, there isnt an apparent way to transfer your C struct knowledge.对于来自 C 背景的人来说,首先似乎分层组织不同的数据类型不是 Lisp 中的首选方法,但除了 CLOS,它是一个成熟的对象系统,如果你只想要结构,那么它太复杂了,除了填充所有内容进入列表,没有明显的方法来转移您的 C 结构知识。

What is the idiomatic Lisp way of hierarchically organizing data which most resembles C structs?最类似于 C 结构的分层组织数据的惯用 Lisp 方式是什么?

-- ——

I think the summary answer to my question would be: For beginner learning purposes, defstruct and/or plists, although "legacy features", can be used, since they most closely resemble C structs, but that they have been largerly superseded by the more flexible defclass/CLOS, which what most Lisp programs use today.我认为我的问题的总结答案是:对于初学者学习目的,defstruct 和/或 plists,虽然“遗留功能”,可以使用,因为它们最接近 C 结构,但它们已被更多的灵活的 defclass/CLOS,这是当今大多数 Lisp 程序所使用的。

This was my first question on SO, so thanks everyone for your time answering it.这是我关于 SO 的第一个问题,所以感谢大家抽出时间来回答。

Use CLOS.使用 CLOS。 It isn't complicated.这并不复杂。

Otherwise use structures.否则使用结构。

If you have a specific question how to use them, then just ask.如果你有一个具体的问题如何使用它们,那就问吧。

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

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

Stuff like that eventually leads to interfaces like Rectangles in CLIM (the Common Lisp Interface Manager).这样的东西最终会导致像CLIM (Common Lisp 接口管理器)中的Rectangles这样的接口。

History历史

To expand on it a bit: Historically 'structures' have been used in some low-level situations.稍微扩展一下:历史上,“结构”已用于一些低级情况。 Structures have single inheritance and slot access is 'fast'.结构具有单继承性,插槽访问“快速”。 Some Lisp dialects have more to structures than what Common Lisp offers.一些 Lisp 方言的结构比 Common Lisp 提供的要多。 Then from the mid-70s on various forms of object-oriented representations have been developed for Lisp.然后从 70 年代中期开始,针对 Lisp 开发了各种形式的面向对象表示。 Most of the representation of structured objects moved from structures to some kind of object-oriented Lisp extension.大多数结构化对象的表示从结构转移到某种面向对象的 Lisp 扩展。 Popular during the 80s were class-based systems like Flavors, LOOPS and others. 80 年代流行的是基于类的系统,如 Flavors、LOOPS 等。 Frame-based or prototype-based systems like KEE Units or Object Lisp were also popular.基于框架或基于原型的系统,如 KEE Units 或 Object Lisp 也很受欢迎。 The first Macintosh Common Lisp used Object Lisp for all its UI and IO facilities.第一个 Macintosh Common Lisp 的所有 UI 和 IO 设施都使用 Object Lisp。 The MIT Lisp machine used Flavors basically everywhere. MIT Lisp 机器基本上到处都使用 Flavors。 Starting in the mid 80s ANSI CL was developed.从 80 年代中期开始,开发了 ANSI CL。 A common OO-system was developed especially for Common Lisp: CLOS.一个通用的面向对象系统是专门为 Common Lisp 开发的:CLOS。 It was based on Flavors and Loops.它基于 Flavors 和 Loops。 During that time mostly nothing was done to really improve structures - besides implementors finding ways to improve the implementation and providing a shallow CLOS integration.在那段时间里,除了实现者寻找改进实现的方法并提供浅层 CLOS 集成之外,几乎没有采取任何措施来真正改进结构。 For example structures don't provide any packing of data.例如,结构不提供任何数据打包。 If there are two slots of 4 bits content, there is no way to instruct Common Lisp to encode both slots into a single 8 bit memory region.如果有两个 4 位内容的插槽,则无法指示 Common Lisp 将这两个插槽编码到一个 8 位内存区域中。

As an example you can see in the Lisp Machine Manual, chapter on structures (PDF) , that it had much more complex structures than what Common Lisp provides.例如,您可以在Lisp 机器手册的结构章节 (PDF)中看到,它的结构比 Common Lisp 提供的结构复杂得多。 Some of that was already present in Maclisp in the 70s: DEFSTRUCT in the Maclisp manual .其中一些已经存在于 70 年代的 Maclisp 中: Maclisp 手册中的 DEFSTRUCT

CLOS, the Common Lisp Object System CLOS,Common Lisp 对象系统

Most people would agree that CLOS is a nice design.大多数人都会同意 CLOS 是一个不错的设计。 It sometimes leads to 'larger' code, mostly because identifiers can get long.它有时会导致“更大”的代码,主要是因为标识符可能会变长。 But there is some CLOS code, like the one in the AMOP book, that is really nicely written and shows how it is supposed to be used.但是有一些 CLOS 代码,比如 AMOP 书中的代码,写得非常好,并展示了应该如何使用它。

Over time implementors had to deal with the challenge that developers wanted to use CLOS, but also wanted to have the 'speed' of structures.随着时间的推移,实现者不得不应对开发人员想要使用 CLOS,但也想要拥有结构的“速度”的挑战。 Which is even more a task with the 'full' CLOS, which includes the almost standard Meta Object Protocol (MOP) for CLOS.这对于“完整”CLOS 来说更是一项任务,其中包括几乎标准的 CLOS 元对象协议 (MOP)。 So there are some tricks that implementors provide.因此,实现者提供了一些技巧。 During the 80s some software used a switch, so it could compiled using structures or using CLOS - CLX (the low-level Common Lisp X11 interface was an example).在 80 年代,一些软件使用 switch,因此它可以使用结构或使用 CLOS - CLX(低级 Common Lisp X11 接口是一个例子)进行编译。 The reason: on some computers and implementations CLOS was much slower than structures.原因:在某些计算机和实现上,CLOS 比结构慢得多。 Today it would be unusual to provide such a compilation switch.今天提供这样的编译开关是不寻常的。

If I look today at a good Common Lisp implementation, I would expect that it uses CLOS almost everywhere.如果我今天看看一个好的 Common Lisp 实现,我会期望它几乎在所有地方都使用 CLOS。 STREAMs are CLOS classes. STREAM 是 CLOS 类。 CONDITIONs are CLOS classes.条件是 CLOS 类。 The GUI toolkit uses CLOS classes. GUI 工具包使用 CLOS 类。 The editor uses CLOS.编辑器使用 CLOS。 It might even integrate foreign classes (say, Objective C classes) into CLOS.它甚至可以将外部类(例如,Objective C 类)集成到 CLOS 中。

In any non-toy Common Lisp implementation CLOS will be the tool to provide structured data, generic behavior and a bunch of other things.在任何非玩具 Common Lisp 实现中,CLOS 都将成为提供结构化数据、通用行为和一系列其他东西的工具。

As mentioned in some of the other answers, in some places CLOS might not be needed.正如其他一些答案中提到的,在某些地方可能不需要 CLOS。

Common Lisp can return more than one value from a function: Common Lisp 可以从一个函数返回多个值:

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

One can store data in closures:可以在闭包中存储数据:

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

For configuration one can use some kind of lists:对于配置,可以使用某种列表:

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

You can bet that I would implement the ship model in CLOS.您可以打赌我会在 CLOS 中实现船舶模型。

A lesson from writing and maintaining CLOS software is that it needs to be carefully designed and CLOS is so powerful that one can create really complex software with it - a complexity which is often not a good idea.编写和维护 CLOS 软件的一个教训是,它需要精心设计,而且 CLOS 如此强大,以至于人们可以用它创建真正复杂的软件——这种复杂性通常不是一个好主意。 Refactor and simplify!重构和简化! Fortunately, for many tasks basic CLOS facilities are sufficient: DEFCLASS, DEFMETHOD and MAKE-INSTANCE.幸运的是,对于许多任务,基本的 CLOS 工具就足够了:DEFCLASS、DEFMETHOD 和 MAKE-INSTANCE。

Pointers to CLOS introductions CLOS 介绍的指针

For a start, Richard P. Gabriel has his CLOS papers for download.首先,Richard P. Gabriel 有他的CLOS 论文可供下载。

Also see:另见:

Examples with defstruct are short and simple because there isn't much to say about them. defstruct例子简短而简单,因为没有太多可说的。 C's struct s are complicated: C 的struct很复杂:

  • memory management内存管理
  • complicated memory layout due to unions, inline nested structures In C, structs are also used for other purposes:由于联合、内联嵌套结构而导致的复杂内存布局在 C 中, structs也用于其他目的:

  • to access memory访问内存

  • due to the lack of polymorphism or ability to pass a value of 'any' type: it is idiomatic to pass around a void*由于缺乏多态性或传递“任何”类型值的能力:传递void*值是惯用的void*
  • due to inability to have other means of passing data;由于无法通过其他方式传递数据; eg, in Lisp you can pass a closure which has the needed data例如,在 Lisp 中,您可以传递一个包含所需数据的闭包
  • due to the lack of advanced calling conventions;由于缺乏高级调用约定; some functions accept their arguments inside structures一些函数在结构中接受它们的参数

In Common Lisp, defstruct is roughly equivalent to Java's/C#'s class : single inheritance, fixed slots, can be used as specifiers in defmethod s (analogous to virtual methods).在 Common Lisp 中, defstruct大致相当于 Java 的/C# 的class :单继承,固定槽,可以用作defmethod的说明defmethod (类似于virtual方法)。 Structures are perfectly usable for nested data structures.结构非常适用于嵌套数据结构。

Lisp programs tend not to use deeply nested structures (Lisp's source code being the primary exception) due to that often more simple representations are possible. Lisp 程序往往不使用深度嵌套的结构(Lisp 的源代码是主要的例外),因为通常更简单的表示是可能的。

I think the idiomatic equivalent of a C struct is to not need to store the data in structs in the first place.我认为 C 结构的惯用等价物首先不需要将数据存储在结构中。 I'd say at least 50% of the C-style code I've ported to Lisp, rather than storing the data in some elaborate structure, I just compute what it is I want to compute.我会说至少有 50% 的 C 风格代码我已经移植到 Lisp,而不是将数据存储在一些复杂的结构中,我只是计算我想要计算的内容。 C needs structs to store everything temporarily because its expressions are so weak. C 需要结构来临时存储所有内容,因为它的表达式非常弱。

If you a specific example of some C-style code, I'm sure we could demonstrate an idiomatic way to implement it in Lisp.如果你有一些 C 风格代码的具体例子,我相信我们可以展示一种在 Lisp 中实现它的惯用方法。

Beyond that, remember that Lisp's s-exps are hierarchical data.除此之外,请记住 Lisp 的 s-exp分层数据。 An if expression in Lisp, for example, is itself hierarchical data.例如,Lisp 中的if表达式本身就是分层数据。

(defclass point ()
          ( x y z))

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

I think this is kind of what I was looking for, can be found here:我认为这就是我一直在寻找的东西,可以在这里找到:

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

Why not use hash tables?为什么不使用哈希表? Every member in the struct can be a key in a hash table.结构中的每个成员都可以是哈希表中的键。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM