Может, будет ещё кому интересно. Опишем, с чего начали. Имеем, к примеру, класс (и метод в нём один):
(defclass |A| ()
((p1
:type integer
:accessor p1
:initarg :p1)))
(defmethod doit ((obj |A|) (value integer))
(format t "~%~A + ~A = ~A~&" (p1 obj) value (+ (p1 obj) value)))
Что мы имеем в стандартной поставке? То, что к свойствам и методам мы можем получить доступ через его аксессор в виде (p1 obj). А хочется
иметь более привычный вид obj.p1 (но это не самое главное);
в случае реализации IDE с использованием ООП для автоподстановки надо объект поместить перед вызовом метода или доступа к свойствам;
Собственно, для этого нам необходимо вмешаться в чтение и интерпретацию данных и определить свои правила (то, что видно как >;, на самом деле просто >):
(defun string-to-symbol (name)
(with-input-from-string (stream name)
(read stream t nil t)))
(defun reverse-symbol-string (symbol-name)
(let ((amp-position (search"&" symbol-name))
(dot-position (search"." symbol-name)))
(if (and (eq amp-position 0)
(and (not (eq dot-position nil))
(> dot-position 1)))
(let ((object (subseq symbol-name (+ amp-position 1) dot-position))
(method (subseq symbol-name (+ dot-position 1))))
`(,(string-to-symbol method) ,(string-to-symbol object)))
`(,(string-to-symbol symbol-name)))))
(defun reverse-symbol (symbol)
(reverse-symbol-string (symbol-name symbol)))
(defun perform-transformation (symbol parameters)
(append (reverse-symbol symbol) parameters))
(defun transform-oo (original)
(if (> (length original) 0)
(let ((function (first original))
(parameters (rest original)))
(if (symbolp function)
(perform-transformation function parameters)
original))
original))
;;; собственно, именно здесь мы и вклиниваемся, то есть
;;; определяем, что во время чтения списка (между скобочками)
;;; мы будем полученный результат трансформировать во что-нибудь
;;; более удобочитаемое для лисп-машины.
(set-macro-character #\(
#'(lambda (stream char)
(let ((original (read-delimited-list #\) stream t)))
(transform-oo original))))
Собственно, тестим (тут '&' может видеться как '&;'):
;;; перепишем старый наш метод класса на иной с продвинутой нотацией
(defmethod doit ((obj |A|) (value integer))
(format t "~%~A + ~A = ~A~&" (&obj.p1) value (+ (&obj.p1) value)))
;;; создадим экземпляр класса
(setf a (make-instance '|A| :p1 4))
;;; а тут вызываем у него метод doit
(&a.doit 3)
В общем, работает....
[4]> (&a.doit 3)
4 + 3 = 7
NIL
Выводы:
интересно;
несколько удобно (можно сделать расширенный синтаксис квадратных скобочек);
в принципе, можно сделать ещё более продвинутую нотацию для свойств — просто &obj.p1 без скобочек (&obj.p1);
Для чего нужен знак '&' в начале объекта — я уже толком и не помню...
Turtle.BAZON.Group пишет:
> Что мы имеем в стандартной поставке? То, что к свойствам и методам мы > можем получить доступ через его аксессор в виде (p1 obj). А хочется > > 1. иметь более привычный вид obj.p1 (но это не самое главное); > 2. в случае реализации IDE с использованием ООП для автоподстановки > надо объект поместить перед вызовом метода или доступа к свойствам;
Любой нормальный лиспер за такое вас будет презирать.
А то и до рукоприкладства дойдет.
Это — лирическое отступление.
LISP — язык с префиксной нотацией (преимущественно, за исключением
спецсинтаксиса вызова CONS() ).
Вы делаете инфикс. Нехорошо.
Метод в LISP в S-выражении стоит на первом месте в списке
не только потому, что это — функция. Метод в LISP НЕ ПРИНАДЛЕЖИТ
никакому классу (объекту класса). В LISP — мультиметоды.
Почему вы его хотите привязать именно к первому его параметру ?
А почему не ко второму ? Или к третьему ?
Или так :
(a b c).some-method
Вы это делаете для IDE ? LISP-овым IDE такое не понравится.
И они замечательно работают без всего этого.
В общем, штука полезна только в одном — попрограммировать
LISP reader.
MZ>Любой нормальный лиспер за такое вас будет презирать. MZ>А то и до рукоприкладства дойдет.
Ну пусть презирает сколько влезет. Тут же демонстрация reader macro.
MZ>LISP — язык с префиксной нотацией (преимущественно, за исключением MZ>спецсинтаксиса вызова CONS() ). MZ>Вы делаете инфикс. Нехорошо.
Я могу сделать хоть постфиксную нотацию, если она мне будет позволять решать мои задачи более эффективно.
MZ>Метод в LISP в S-выражении стоит на первом месте в списке MZ>не только потому, что это — функция. Метод в LISP НЕ ПРИНАДЛЕЖИТ MZ>никакому классу (объекту класса). В LISP — мультиметоды.
То, что есть в лисп и писали 2 года и сделали объектную систему под названием CLOS для всего и для ничего в частности, не говорит, что она есть самая удобная в каком-нибудь частном случае. Благо, лисп позволяет сделать так, как удобно.
MZ>Почему вы его хотите привязать именно к первому его параметру ? MZ>А почему не ко второму ? Или к третьему ? MZ>Или так : MZ>(a b c).some-method
К примеру. Можно и так.
MZ>Вы это делаете для IDE ? LISP-овым IDE такое не понравится. MZ>И они замечательно работают без всего этого.
Потому что и лисповых IDE то, грубо говоря, не очень, да и сами не очень. Знаю две более или менее юзабельные (LispWorks и SLIME), но если подумать, то они могли бы и больше. Или хотя бы без меньших глюков.
MZ>В общем, штука полезна только в одном — попрограммировать MZ>LISP reader.
Ахха. Поэтому тема такая и выбрана, а не "Инфиксная нотация в LISP"
Turtle.BAZON.Group пишет:
> Потому что и лисповых IDE то, грубо говоря, не очень, да и сами не > очень. Знаю две более или менее юзабельные (LispWorks и SLIME), но если > подумать, то они могли бы и больше. Или хотя бы без меньших глюков.
LispWorks слабоват в виде IDE, это — да. А Slime вполне хорош.
Или его реинкарнация на базе Eclipse — CUSP plugin.
На самом деле функциональность SLIME -а достаточно сильно зависит
от реализации лиспа, с которой он работает, от сервисов, которые
она предоставляет, поэтому надо попробовать все, чтобы осознанно
что-то говорить. Я работал с SBCL, и то вполне хорошо.
Здравствуйте, MasterZiv, Вы писали:
MZ>LispWorks слабоват в виде IDE, это — да. А Slime вполне хорош. MZ>Или его реинкарнация на базе Eclipse — CUSP plugin.
Вот эклипсовый cusp совсем не понял. Хотя пытался. Может, давно пытался, когда он ещё не такой юзабельный был.
MZ>На самом деле функциональность SLIME -а достаточно сильно зависит MZ>от реализации лиспа, с которой он работает, от сервисов, которые MZ>она предоставляет, поэтому надо попробовать все, чтобы осознанно MZ>что-то говорить. Я работал с SBCL, и то вполне хорошо.
Я тоже работаю с SBCL. Для меня на данный момент альтернативы нет. Но если сопоставить IDEA для java и SLIME для lisp — ломка страшная.
Turtle.BAZON.Group пишет:
> Вот эклипсовый cusp совсем не понял. Хотя пытался. Может, давно пытался, > когда он ещё не такой юзабельный был.
CUSP — это стандартный SWANK + аналог SLIME, переписанный в виде
плагина к эклипсу. В общем-то очень хорошая идея.
Но немного хромает исполнение, что-то там вечно подглючивает.
Но в целом, если чел. не может смириться с Emacs-ом, что
несложно, сам долго не мог его постигнуть, то — вполне себе вариант.
А ежели что, можно допилить напильником, ибо opensource.
> Я тоже работаю с SBCL. Для меня на данный момент альтернативы нет. Но > если сопоставить IDEA для java и SLIME для lisp — ломка страшная.
Для лиспа всей этой IDE-шной лабуды на самом деле и не надо в таком
количестве, там язык другой, кодогенерации в офигенном объеме делать
не надо. Там другое нужно — голова разработчика.
Здравствуйте, Turtle.BAZON.Group, Вы писали:
TBG>Может, будет ещё кому интересно. Опишем, с чего начали. Имеем, к примеру, класс (и метод в нём один): TBG>Для чего нужен знак '&' в начале объекта — я уже толком и не помню...
про reader macros интересно, вот только пример спорный.
Всмысле для CL есть CLOS, и пытаться изменить нотацию это как изобретать lisp без скобок. +Есть прямой недостаток:
у generic-functions один набор параметров -- т.е. тривиально не сделать
(foo a b)
(foo a b c d e :key key1)
kzn пишет:
> Всмысле для CL есть CLOS, и пытаться изменить нотацию это как изобретать > lisp без скобок. +Есть прямой недостаток: > у generic-functions один набор параметров -- т.е. тривиально не сделать > (foo a b) > (foo a b c d e :key key1)
Почему же , можно,
(defgeneric foo (a b (c nil) (d nil) (e nil) :key key1)) ...)
А вот как обрабатывать такое:
(defgeneric foo ( :key a b (c nil) (d nil) (e nil) ) ...)
MZ>CUSP — это стандартный SWANK + аналог SLIME, переписанный в виде MZ>плагина к эклипсу. В общем-то очень хорошая идея. MZ>Но немного хромает исполнение, что-то там вечно подглючивает.
Вот-вот. Это помню.
MZ>Но в целом, если чел. не может смириться с Emacs-ом, что MZ>несложно, сам долго не мог его постигнуть, то — вполне себе вариант. MZ>А ежели что, можно допилить напильником, ибо opensource.
Допиливать желания то как раз не очень бывает.
MZ>Для лиспа всей этой IDE-шной лабуды на самом деле и не надо в таком MZ>количестве, там язык другой, кодогенерации в офигенном объеме делать MZ>не надо. Там другое нужно — голова разработчика.
Голова разработчика — это необходимость в любом языке.