LINUX.ORG.RU

А бывает ли в Common Lisp объектная модель на сообщениях?

 


1

6

Как в ruby/smalltalk.

Или умерла вместе с Lisp machines/Genera/Flavors?

Хотелось бы знать, почему CLOS вытеснил все альтернативы. Плюс у сообщений в том, что для разных классов сообщения не обязаны иметь одинаковое количество параметров.

Ну и, в том же Racket, классы/объекты как раз работают на сообщениях.

★★★★★
Ответ на: комментарий от dave

в твоем примере указаны два разных метода add: и add:after:

Ну так keyword в Smalltalk считается частью имени. А в смысле CL там количество параметров всегда равно количеству двоеточий в имени метода.

Того же можно добиться в CL сигнатурой (add objeсt &key &allow-other-keys). Но ведь никто такие сигнатуры в API не использует. Вот и получается, что найти короткое имя для новой функции сродни сделать почтовый ящик без цифр на mail.ru.

monk ★★★★★
() автор топика
Ответ на: комментарий от anonymous

есть более аккуратные языки, изначально разумно спроектированные: схема, eulisp, ISO ISLISP.

Ты разве историю появления ISLISP не знаешь? Значит, рассказываю: омереканские скобочники активно общались с европейскими (пьянки, кокаиновые дорожки, девки и т.п.), всё шло пучком. Потом ДАРПА выделила денег на стандартизацию лиспа, но мало, поэтому омереканцы, хоп!, стандарт наваяли без европеоидов. Чтобы сократить волокиту, а то денег не хватит. Как ты правильно отметил, слепили в одну кучу две с половиной популярные на тот момент реализации, поэтому кое-какие непонятки получились прям в свежем, казалось бы, стандарте.

Но речь не про несуразицы в ANSI, а про европейцев. Европейцы эти, значит, обиделись, и в отместку наваяли ISO-стандарт. Нате, мол, вам, янки! Да только там стандарта всего страниц 170 супротив 1000 в ANSI, поэтому это непонятная игрушка, которую в одно рыло можно реализовать. Вот ANSI CL в одно рыло опухнешь реализовывать.

mv ★★★★★
()
Ответ на: комментарий от monk

Того же можно добиться в CL сигнатурой (add objeсt &key &allow-other-keys). Но ведь никто такие сигнатуры в API не использует

Вот именно, что можно, но я, по всему видно, не зря предположил, что вы не поняли мультиметоды.

В cl получаем отдельно append-item и insert-item-after.

А ничего, что insert-item-after специализируется по 3 параметрам? Ну-ка повтори-ка это на смолтолке.

no-such-file ★★★★★
()
Ответ на: комментарий от no-such-file

А ничего, что insert-item-after специализируется по 3 параметрам? Ну-ка повтори-ка это на смолтолке.

Там оно не надо. То же самое пишется через

(defun insert-item-after (list node new-node)
  (unless (typep new-node dlist-container-node)
     (setf new-node (make-node-for-container list item)))
  ...)

А там для этого наворочено 4 метода с частичным дублированием кода.

monk ★★★★★
() автор топика
Ответ на: комментарий от monk

multi-dipatch, конечно нужен, но реально это исключительные случаи (и тогда действительно не нужно считать, что метод принадлежит классу). А в 95% случаев нужен именно метод класса/объекта, а CL их кидает все в общий список...

Вообще есть идея.

Если будет конструкция

(defmessage (list dlist-container) 
            (:add (new-node dlist-container-node) :after node)
  ...)

в смысле с диспатчингом по ключевым параметрам, будет удобно?

Использовать:

(@ my-list (:add item1) 
           (:add item2 :after item1) 
           (:add item3))
monk ★★★★★
() автор топика
Ответ на: комментарий от monk

А в 95% случаев нужен именно метод класса/объекта, а CL их кидает все в общий список...

Ок, еще раз. Ваш тупой дженерик:

(defgeneric text (object &key) ...)

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

Если будет конструкция

Это будет не как в смолтолке, т.к. в смолтолке методы не выбираются в зависимости от параметров сообщения. Это не будет работать вообще, т.к. ключи можно не указывать, а как тогда выбирать вызываемый метод, если не заданы все классы по которым специализируется дженерик?

Вы упорно пытаетесь использовать специализаторы для объявления типа, но они не для этого предназначены, поймите.

no-such-file ★★★★★
()
Ответ на: комментарий от no-such-file

Ок, еще раз. Ваш тупой дженерик...Все как в смолтолке.

Вот только я не могу при этом назвать метод ни length, ни finish, ни collect... Потому как почти тысяча функций входит в стандарт CL, а дженерики с ними разделяют пространство имён.

Это не будет работать вообще, т.к. ключи можно не указывать

Ключи, объявленные в defmessage обязательны. Если ключ не указан, то должен быть defmessage с описанием, что делать при этом. Аналог в данном случае не (defun ... (... &keys)), а смоллтолковский подход.

Вы упорно пытаетесь использовать специализаторы для объявления типа

Не распарсил. Тип может объявить только defclass при чём тут специализаторы на методы? Я лишь хочу разнести пространство методов (сделать его зависимым от класса) и прочих функций (хоть defgeneric, хоть defun)

monk ★★★★★
() автор топика
Ответ на: комментарий от naryl

Реализация есть? :)

Скоро будет. Эффективное алгоритмическое решение (чтобы было не медленнее, чем CLOS) уже есть. Осталось аккуратно написать.

monk ★★★★★
() автор топика
Ответ на: комментарий от monk

Вот только я не могу при этом назвать метод ни length, ни finish, ни collect...

Я лишь хочу разнести пространство методов (сделать его зависимым от класса) и прочих функций

Аа. Ну а в чем проблема сделать дженерик (defgeneric send (object message &key)). Благо CLOS позволяет диспечеризацию как по object, так и по method. Делаете класс (defclass message ...). Сообщения создаете как объекты класса message и делаете методы send, либо специализированные для каждого объекта класса message (диспечеризация за счет CLOS), либо в объект класса message заворачиваете параметры, по которым метод выбирает как ему работать. Опять же сообщения можно будет наследовать и т.п. Получается даже круче, чем вам надо.

no-such-file ★★★★★
()
Последнее исправление: no-such-file (всего исправлений: 1)
Ответ на: комментарий от no-such-file

Ну а в чем проблема сделать дженерик (defgeneric send (object message &key)). Благо CLOS позволяет диспечеризацию как по object, так и по method.

...по message. Ровно это и делаю. Просто удивляет, что новички через одного спрашивают, как сделать, чтобы пространство имён было ограничено классом (да, как в Java), но никто не сделал нормального решения.

monk ★★★★★
() автор топика
Ответ на: комментарий от monk

А в 95% случаев нужен именно метод класса/объекта, а CL их кидает все в общий список...

Для создания области видимости функций используй пакеты.

mv ★★★★★
()
Ответ на: комментарий от monk

Вот только я не могу при этом назвать метод ни length, ни finish, ни collect... Потому как почти тысяча функций входит в стандарт CL, а дженерики с ними разделяют пространство имён.

Нормальные люди код пишут в своих пакетах. Стандартные имена спокойно затеняются, если это вдруг надо.

mv ★★★★★
()
Ответ на: комментарий от mv

Нормальные люди код пишут в своих пакетах.

Пробовал. После этого использование выглядит примерно так:

(define-binary-class xbase-field ()
  ((name (ru.slavsoft.dbf:db-field-name :length 11))
   (field-type com.gigamonkeys.binary-data.common-datatypes:u1)
   (reserved com.gigamonkeys.binary-data.common-datatypes:u4)
   (size com.gigamonkeys.binary-data.common-datatypes:u1)
   (precision com.gigamonkeys.binary-data.common-datatypes:u1)
   (reserved2 com.gigamonkeys.binary-data.common-datatypes:u2)
   (workspace com.gigamonkeys.binary-data.common-datatypes:u1)
   (multi-user com.gigamonkeys.binary-data.common-datatypes:u2)
   (set-fields com.gigamonkeys.binary-data.common-datatypes:u1)
   (reserved3 (discard :length 7))
   (index com.gigamonkeys.binary-data.common-datatypes:u1)))
monk ★★★★★
() автор топика
Ответ на: комментарий от monk

Спасибо. А... в чём тогда проблема с пакетами? Вспомните джавы и хаскели где каждый файл начинается с пары страничек импортов с переименованиями. Никто вроде не против. :)

Было бы интересно скрестить advanced-readtable и named-readtables.

naryl ★★★★★
()
Ответ на: комментарий от mv

пакетов по короткому алиасу

Просто даже с короткими алиасами сплошь и рядом будут куски вида

(defun present-name (employee)
  (let ((address (employee:address employees))
    (string+ (employee:name employee) " " 
             (employee:surname employee) " " 
             (employee:patronymic-name employee) " living at "
             (address:region address) " " 
             (address:city address) " " 
             (address:street address))

Костыль, конечно, есть, в том же advanced-readtable

(defun present-name (employee)
  employee:(let ((address (address employees))
    address:(string+ (name employee) " " 
             (surname employee) " " 
             (patronymic-name employee) " living at "
             (region address) " " 
             (city address) " " 
             (street address))

но этот вариант имеет то же неудобство, что и with-all-slots. Что, если позже в пакет address добавят функцию name? present-name станет некорректной (надо будет заменять name на employee:name).

monk ★★★★★
() автор топика
Ответ на: комментарий от naryl

пары страничек импортов с переименованиями

Так в том и дело.

1. Многие (com.informatimago, iterate) пишут так, что подразумевают use-package на свои пакеты.

2. При большом количестве импортируемых пакетов local-nickname не спасает, потому в коротких псевдонимах будешь сам путаться при чтении. Максимум, можно переименовывать com.gigamonkeys.binary-data.common-datatypes в common-datatypes (или common-data, но в com-dat уже нельзя).

Ну и просто не нравится мне в каждой строчке имя типа указывать. Как будто на plain C пишешь.

monk ★★★★★
() автор топика
Ответ на: комментарий от naryl

Было бы интересно скрестить advanced-readtable и named-readtables

Там есть более мощная фича set-symbol-readmacro. Позволяет делать что-то вроде

html:[html [body [table (get-data sql:[select * from db])]]]

В смысле, здесь используется два переопределения квадратной скобки: html:[ и sql:[

named-readtables позволяет менять только на уровне файла.

monk ★★★★★
() автор топика
Ответ на: комментарий от monk

А, понял. В advanced-readtables символьные ридмакры покрывают большУю часть юз-кейсов named-readtables. Но для работы с обычными ридмакрами она остаётся незаменимой. Может немного сбивать с толку отсутствие '#'. ЕМНИП где-то в обсуждении было предложено что-то такое:

#!html:[html [body [table (get-data #!sql:[select * from db])]]]

naryl ★★★★★
()
Ответ на: комментарий от naryl

Может немного сбивать с толку отсутствие '#'

Вообще-то # подразумевает один символ после. И ломать это не лучшая идея. Advanced-readtable позволяет разнести по пакетам переопределенеие [] и {}. С учётом того, что в стандарте они не используются, никого с толку не собъет.

В случае named-readtable было бы

(in-readtable :sql)
(setf data (get-data [select * from db]))

(in-readtable :html)
[html [body [table data]]]

Для включения/выключения всяких #t, #Dfoo.bar и прочее, можно использвать named-readtable (и тут они с advanced-readtable никак не конфликтуют).

monk ★★★★★
() автор топика
Ответ на: комментарий от mv

Ты разве историю появления ISLISP не знаешь?

T, Le Lisp, EuLisp, Scheme + Kyoto Lisp => ISLISP

Maclisp, InterLisp, ZetaLisp => Common Lisp

Но речь не про несуразицы в ANSI, а про европейцев

мне в этом больше нравятся японцы и проект TRON. вот ведь Kyoto Lisp + TRON => ISLISP интересная ветка получилась.

только анимешников не хватает, стандарты перевести на язык северных варваров. так и не знают, невежественные, что конструкция разумнее получилась, и насаждают свои «барочные технологии» Викторианского веку, стимпанкеры эдакие.

anonymous
()
Ответ на: комментарий от anonymous

конструкция разумнее получилась

в дупу «разумную конструкцию», если нет быстрой и «кастомизируемой» свободной реализации с пятнашками и медсестричками

yyk ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.