Какой идиоматический эквивалент структур C в Лиспе? - PullRequest
20 голосов
/ 28 декабря 2010

В языках C-типа сильный упор делается на структуры / записи и объекты с самого начала и в каждой вводной книге. Затем их полные системы предназначены для управления такими структурами, их взаимоотношениями и наследованием.

В документации по Лиспу обычно можно найти 1-2 страницы о том, как Лисп "также" имеет defstruct, простой пример, и обычно это так. Кроме того, вложение структур вообще никогда не упоминается.

Для кого-то, происходящего из C-фона, сначала кажется, что иерархическая организация различных типов данных не является предпочтительным методом в Лиспе, но кроме CLOS, который является полноценной объектной системой и слишком сложным, если вы просто хотите структуры, и отдельно от объединения всего в списки нет очевидного способа передать ваши знания структуры C.

Каков идиоматический способ Lisp для иерархической организации данных, который больше всего напоминает структуры C?

-

Я думаю, что краткий ответ на мой вопрос был бы следующим: для целей обучения новичков можно использовать defstruct и / или plists, хотя «унаследованные функции», так как они наиболее близко напоминают структуры C, но они были в большей степени заменены более гибким defclass / CLOS, который сегодня используют большинство программ на Лиспе.

Это был мой первый вопрос по SO, поэтому спасибо всем, что уделили мне время.

Ответы [ 6 ]

22 голосов
/ 28 декабря 2010

Используйте CLOS. Это не сложно.

В противном случае используйте структуры.

Если у вас есть конкретный вопрос, как их использовать, просто спросите.

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

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

Подобные вещи в конечном итоге приводят к таким интерфейсам, как Прямоугольники в CLIM (Диспетчер интерфейсов Common Lisp).

История

Чтобы расширить это немного: исторически «структуры» использовались в некоторых ситуациях низкого уровня. Структуры имеют единственное наследование, и доступ к слотам «быстрый». Некоторые диалекты Лисп имеют больше структур, чем предлагает Common Lisp. Затем с середины 70-х годов для Lisp были разработаны различные формы объектно-ориентированных представлений. Большая часть представления структурированных объектов перешла из структур в некое объектно-ориентированное расширение Lisp. В 80-х годах популярными были такие системы, как Flavors, LOOPS и другие. Системы на основе фреймов или прототипов, такие как KEE Units или Object Lisp, также были популярны. Первый Macintosh Common Lisp использовал Object Lisp для всех своих функций пользовательского интерфейса и ввода-вывода. Машина MIT Lisp использовала ароматизаторы практически везде. Начиная с середины 80-х годов был разработан ANSI CL. Общая OO-система была разработана специально для Common Lisp: CLOS. Он был основан на ароматах и ​​петлях. За это время практически ничего не было сделано для реального улучшения структур - кроме разработчиков, которые находили способы улучшить реализацию и обеспечивали поверхностную интеграцию CLOS. Например, структуры не предоставляют никакой упаковки данных. Если есть два слота с 4-битным содержимым, нет способа дать команду Common Lisp кодировать оба слота в одну 8-битную область памяти.

В качестве примера вы можете видеть в руководстве по машинам Lisp, глава о структурах (PDF) , что у него были гораздо более сложные структуры, чем в Common Lisp. Часть этого уже присутствовала в Maclisp в 70-х годах: DEFSTRUCT в руководстве Maclisp .

CLOS, Common Lisp Object System

Большинство людей согласятся с тем, что CLOS - хороший дизайн. Иногда это приводит к «большему» коду, в основном потому, что идентификаторы могут быть длинными Но есть некоторый код CLOS, такой как код в книге AMOP, который действительно хорошо написан и показывает, как он должен использоваться.

Со временем разработчики должны были решить проблему, заключающуюся в том, что разработчики хотели использовать CLOS, но также хотели иметь «скорость» структур. Это еще более сложная задача для «полной» CLOS, которая включает в себя почти стандартный Meta Object Protocol (MOP) для CLOS. Таким образом, есть некоторые хитрости, которые предоставляют разработчики. В течение 80-х годов некоторые программы использовали коммутатор, поэтому он мог компилироваться с использованием структур или с использованием CLOS - CLX (например, низкоуровневый интерфейс Common Lisp X11). Причина: на некоторых компьютерах и реализациях CLOS был намного медленнее, чем структуры. Сегодня было бы необычно представить такой ключ компиляции.

Если я сегодня посмотрю на хорошую реализацию Common Lisp, я ожидаю, что она использует CLOS почти везде. ПОТОКИ - это классы 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

Для начала у Ричарда П. Габриэля есть документы CLOS для скачивания.

Также см .:

5 голосов
/ 28 декабря 2010
4 голосов
/ 28 декабря 2010

Примеры с defstruct короткие и простые, потому что о них особо нечего сказать. C struct s сложны:

  • управление памятью
  • сложное расположение памяти из-за объединений, встроенных вложенных структур В C structs также используются для других целей:

  • для доступа к памяти

  • из-за отсутствия полиморфизма или способности передавать значение «любого» типа: идиоматично передавать значение void*
  • из-за невозможности иметь другие средства передачи данных; например, в Лиспе вы можете передать замыкание с необходимыми данными
  • из-за отсутствия предварительных соглашений о вызовах; некоторые функции принимают свои аргументы внутри структур

В Common Lisp defstruct примерно эквивалентно class Java / C #: одиночное наследование, фиксированные слоты, могут использоваться в качестве спецификаторов в defmethod s (аналогично virtual методам). Структуры идеально подходят для вложенных структур данных.

Программы на Лиспе, как правило, не используют глубоко вложенные структуры (исходный код на Лиспе является основным исключением) из-за того, что часто возможны более простые представления.

2 голосов
/ 23 марта 2012
(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 у

2 голосов
/ 28 декабря 2010

Я думаю, что идиоматический эквивалент структуры C состоит в том, что в первую очередь не нужно хранить данные в структурах.Я бы сказал, что по крайней мере 50% кода в стиле C, который я перенес на Lisp, вместо того, чтобы хранить данные в какой-то сложной структуре, я просто вычисляю, что именно я хочу вычислить.C нуждается в структурах для временного хранения всего, потому что его выражения очень слабы.

Если вы приведете конкретный пример некоторого кода в стиле C, я уверен, что мы могли бы продемонстрировать идиоматический способ реализовать его в Lisp.*

Кроме того, помните, что s-exps в Lisp являются иерархическими данными.Например, выражение if в Лиспе само по себе является иерархическими данными.

0 голосов
/ 28 декабря 2010

Почему бы не использовать хеш-таблицы?Каждый член в структуре может быть ключом в хэш-таблице.

...