Какой идиоматический эквивалент структур C в Лиспе?

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

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

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

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

-

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

Это был мой первый вопрос о SO, так что спасибо всем за ваше время ответить на него.

6 ответов

Решение

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

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

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

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

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

Подобные вещи в конечном итоге приводят к интерфейсам типа Rectangles в CLIM (Common Lisp Interface Manager).

история

Чтобы расширить это немного: исторически "структуры" использовались в некоторых ситуациях низкого уровня. Структуры имеют единственное наследование, а доступ к слотам "быстрый". Некоторые диалекты Лисп имеют больше структур, чем предлагает Common Lisp. Затем с середины 70-х годов для Лисп были разработаны различные формы объектно-ориентированных представлений. Большая часть представления структурированных объектов перешла из структур в некое объектно-ориентированное расширение 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 для скачивания.

Также см:

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

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

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

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

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

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

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

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

Кроме того, помните, что S-EXP 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)))))

Я думаю, что это то, что я искал, можно найти здесь:

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

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

Другие вопросы по тегам