Re[11]: Lisp
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 14.07.05 10:18
Оценка: 1 (1)
Здравствуйте, aka50, Вы писали:

AVK>>Нет, если написать <value-of select="helper:Capitalize(@name)"/>.


A>сорри за невежество, но google не помог. helper — это че за неймспейс такой?


На смайлик обратил внимание? Это намек на то, что подобные алгоритмы я напишу на шарпе и подключу как extension, вместо того чтобы извращаться на xslt.
... << RSDN@Home 1.2.0 alpha rev. 558>>
AVK Blog
Re[12]: Lisp
От: aka50 Россия  
Дата: 14.07.05 10:22
Оценка:
Здравствуйте, Cyberax, Вы писали:

C>А кто сказал, что мне нужен именно DOM? Для XMLя есть еще и SAX (тоже

C>стандартизованный, кстати).

Хорошо. Уговорил. libexpat весит 200к. Но в 200к можно запросто не то что лисп,
схему запихнуть (там же по ссылке лежит scheme инерпретатор чуть больше 200к)

Но к чему это? Для чего тебе тут лисп? Если рассматривать альтернативные решения XML XSLT то надо смотреть в каком контексте:
1 Если просто данные передавать, то можно sexpr
2 Процессинг — sexrp + простенький lisp.
3 Если RPC или скриптование — lisp.
4 Если полноценная система типа .Net или Java — common lisp (дохрена весит, почти как perl или python, ну шустрее в разы) + ffi.

Это все конечно реализуемо, но при этом синтаксис получается еще более "страшным" чем у lisp. (4-й пункт вроде токо XUL — аналог)
Сколько эти решения весят? Насколько они преносимы? (вот уже второй день пытаюсь в JanusSvc Dataset из SOAP s:any выдернуть.
нифига себе стандартизация. Изврат полный).

По этому собственно и спор. Что такого нового в этих технологиях чего нет в старых технологиях 60-ти летней давности?
Re[12]: Lisp
От: aka50 Россия  
Дата: 14.07.05 10:24
Оценка:
Здравствуйте, AndrewVK, Вы писали:

AVK>Здравствуйте, aka50, Вы писали:


AVK>>>Нет, если написать <value-of select="helper:Capitalize(@name)"/>.


A>>сорри за невежество, но google не помог. helper — это че за неймспейс такой?


AVK>На смайлик обратил внимание? Это намек на то, что подобные алгоритмы я напишу на шарпе и подключу как extension, вместо того чтобы извращаться на xslt.

ааа . Ну тогда в лиспе есть ffi. Но фишка в том, что в лиспе _не необходимости_ вызывать ниче. В нем все реализуется достаточно просто
понятно и главное на нем самом .
Так что думаю 1:0 в пользу лиспа
Re[13]: Lisp
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 14.07.05 10:27
Оценка:
Здравствуйте, aka50, Вы писали:

A>По этому собственно и спор. Что такого нового в этих технологиях чего нет в старых технологиях 60-ти летней давности?


Может быть удобства использования для средненького программиста, не желающего расширять сознание, а просто получающего зарплату за фиксированный объем работы в течении 40-ка часовой рабочей недели?
... << RSDN@Home 1.1.4 stable rev. 510>>


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[13]: Lisp
От: Mamut Швеция http://dmitriid.com
Дата: 14.07.05 10:34
Оценка:
A>Это все конечно реализуемо, но при этом синтаксис получается еще более "страшным" чем у lisp. (4-й пункт вроде токо XUL — аналог)
A>Сколько эти решения весят? Насколько они преносимы? (вот уже второй день пытаюсь в JanusSvc Dataset из SOAP s:any выдернуть.
A>нифига себе стандартизация. Изврат полный).

Как выдернешь, свистни
Автор: Mamut
Дата: 12.07.05
А то меня тоже интересуют методы борьбы с.


dmitriid.comGitHubLinkedIn
Re[14]: Lisp
От: aka50 Россия  
Дата: 14.07.05 10:35
Оценка: -1
Здравствуйте, eao197, Вы писали:

E>Может быть удобства использования для средненького программиста, не желающего расширять сознание, а просто получающего зарплату за фиксированный объем работы в течении 40-ка часовой рабочей недели?


Ну опять о простых программерах. Простой программер тоже не шибко обрадуется на XSLT писать. ИМХО лисп проще.
Re[13]: Lisp
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 14.07.05 10:37
Оценка:
Здравствуйте, aka50, Вы писали:

A>ааа . Ну тогда в лиспе есть ffi. Но фишка в том, что в лиспе _не необходимости_ вызывать ниче. В нем все реализуется достаточно просто


Замечательно.

A>понятно и главное на нем самом .

A>Так что думаю 1:0 в пользу лиспа

Я кажется объяснял, что я не ставлю задачу показать что лисп никуда не годен.
... << RSDN@Home 1.2.0 alpha rev. 558>>
AVK Blog
Re[2]: AST-based solution
От: fionbio  
Дата: 14.07.05 10:37
Оценка: 54 (9)
[ Эх, обогнали меня Вчера накалякал пример, хоть и башка
была весь день какая-то мутная — странно, не пил вроде. Запостить
вчера моральных сил не хватило ]

Попробую привести решение в духе Лиспа

Если я правильно понимаю, то для публики может представлять
интерес несколько более общее решение задачи. В связи с этим
я хотел бы привести пример с использованием AST. Преимущества
такого подхода, думаю, известны — на основе этой инфраструктуры
можно легко создавать другие, более сложные и полезные генераторы
кода (см R#). Кроме того, мы фактически можем применять подобие
lisp macros к C#.

Если коллег интересует более компактное решение, я могу привести
и сокращённый вариант без деревьев. Также могу сказать, что для Лиспа
есть готовые либы для работы с text templates, например, CL-EMB
(в добавок я ещё свою достаточно удобную примочку как-то написал
для темплейтенья сырцов, я её использовал для VB.NET).

Я буду использовать стандартный Common Lisp Pretty Printer.
Это cразу исключает CLisp, т.к. AFAIK в нём эта часть не доделана.
Код работает с SBCL, Allegro, LispWorks; должен работать с CMUCL.
Данный pretty printer представляет из себя специфическое чудо техники
и конфигурируем в такой степени, что в идеале можно на входе давать
Lisp (списочные структуры), а на выходе получать C#. В силу природной
лени (и, возможно, опыта программирования на Perl ) я воспользовался
в паре мест не особо читабельными строками формата, за что прошу меня
извинить (можно было бы обойтись и без них).

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

Обработанный colorize'ом вариант — тут:
http://depni.sinp.msu.ru/~ivan_iv/lisp/sharpclass.html

Сам исходник — тут:
http://depni.sinp.msu.ru/~ivan_iv/lisp/sharpclass.lisp

Для пущей интересности задачу немного расширим — пусть
для пропертей генерятся не только getter'ы, но и setter'ы,
плюс генерится конструктор без аргументов (в добавок к
конструктору с аргументами) и все классы заворачиваются
в общий namespace

В качестве исходных данных вместо

<objects>
    <object name="Obj1">
        <property name="prop1" type="int"/>
        <property name="prop2" type="string"/>
    </object>
</objects>


мы будем использовать

(namespace "MyNS"
 (object "Obj1"
  (property "prop1" "int")
  (property "prop2" "string")
  (property "dblprop" "double"))
 (object "Obj2"
  (property "someprop" "object[]")))


Следует учесть, что символы namespace, object и property
данным генератором не используются и добавлены здесь для
читабельности.

Вводим промежуточное представление — AST.
Идея заключается в следующем — у нас есть дерево, в
виде символьного выражения записываемое, например, так:
(:namespace "MyTestNS"
 (:class "MyTestClass"
  (:field "int" "_someprop")
  (:constructor "MyTestClass" ((:arg "int" "someprop"))
   (:comment "This is a test")
   (:setf (:id "_someprop") (:id "someprop")))
  (:property "int" "SomeProp"
   (:get (:return (:id "_someprop")))
   (:set (:setf (:id "_someprop") (:id "value"))))
  (:property "int" "AnotherProp"
   (:get (:return 0)))))


В виде XML его можно было бы записать, например, следующим образом:
<namespace name="MyTestNS">
  <class name="MyTestClass">
    <field name="_someprop" type="int"/>
    <constructor name="MyTestClass">
      <args>
        <arg name="someprop" type="int"/>
      </args>
      <body>
        <set>
          <lvalue>
            <identifier name="_someprop">
          </lvalue>
          <rvalue>
            <identifier name="someprop">
          </rvalue>
        </set>
      </body>
    </constructor>
    <property name="SomeProp" type="int">
      ...
    </property>
    ...
</namespace>


Данный AST является достаточно упрощённым, но для наших целей этого
хватит.

Далее, нам надо настроить pretty-printer. Мы определяем способы печати
различных узлов дерева (data-driven approach). Для этого нам нужен следующий framework:

;;; AST printer, much more concise than your CodeDOM and perhaps R# :-P
;;; Can be easily extended to support other language constructs &
;;; several languages simultaneously

;; pretty-print dispatch table: type -> printing func correspondence
(defvar *dispatch* (copy-pprint-dispatch))

(defun ast-print (x &optional (stream *standard-output*))
  "Print the expression x using AST dispatch rules"
  (write x :pretty t :pprint-dispatch *dispatch* :stream stream))

(defun ast-print-form (stream form)
  "Print the AST node (form)"
  (if (and (symbolp (first form))
           (get (first form) 'ast-form))
      (funcall (get (first form) 'ast-form) stream form)
      (error "unknown form: ~S" form)))

;; set dispatch function for cons type in our pretty-print dispatch table
(set-pprint-dispatch 'cons #'ast-print-form 0 *dispatch*)

(defmacro defprinter (name args &body body)
  "Define a printer for specified AST node type"
  (let ((func-name (intern (format nil "PRINT-FORM-~A" name)))
        (item (gensym)))
    `(progn
       (defun ,func-name (stream ,item)
         (destructuring-bind ,args (rest ,item)
           ,@body))
       (setf (get ',name 'ast-form) ',func-name))))


Функция (ast-print ...) печатает AST с использованием созданной
конфигурации. Макрос defprinter позволяет задавать обработчики
узлов дерева с указанием структуры. Функция ast-print-form является
обработчиком, печатающим значения типа cons — он, собственно,
вызывает нужный хендлер.

Прежде, чем приводить обработчики узлов, давайте посмотрим,
что они дают.

;; определяем простую функцию для печати - чтобы возвращаемое
;; значение не мешало обзору

CL-USER> (defun p (x) (ast-print x) nil)
P

;; играемся

CL-USER> (p '(:id "qwerty"))
qwerty
NIL
CL-USER> (p '(:return (:id "qwerty")))
return qwerty;
NIL
CL-USER> (p '(:property "int" "Qwerty" (:get (:return (:id "qwerty")))))
public int Qwerty
{
    get
    {
        return qwerty;
    }
}
NIL
CL-USER> (p '(:property "int" "Qwerty"
          (:get (:return (:id "qwerty")))
          (:set (:setf (:id "qwerty") (:id "value")))))
public int Qwerty
{
    get
    {
        return qwerty;
    }
    set
    {
        qwerty = value;
    }
}
NIL


Вроде как полезненно. Способствует. Посмотим, что внутрях.
Там есть одна утилитная функция с кривой строкой формата, которая
печатает ... { ... } с новыми строками и индентацией, плюс обработчики.

;;; AST printing specs for C#
;;; (write other specs, get VB.NET, Java, C++, Fortran, etc.)

;; please note that the following function could be writen in a more
;; clear way using pprint-* funcs, but now I'm just too lazy
(defun print-statement-with-body (stream body two-newlines fmt &rest args)
  "Print the statement with brace-enclosed body"
  (format stream
          (if two-newlines
              "~?~:@_~@<{~4i~{~:@_~w~^~:@_~}~i~:@_}~:>"
              "~?~:@_~@<{~4i~{~:@_~w~}~i~:@_}~:>")
          fmt args body))

;; identifier - printed literally
(defprinter :id (id)
  (write-string id stream))

;; private int x;
(defprinter :field (type name)
  (format stream "private ~a ~a;" type name))

;; public int SomeProp { ... }
(defprinter :property (type name &rest body)
  (print-statement-with-body stream body nil "public ~a ~a" type name))

;; get { ... }
(defprinter :get (&rest body)
  (print-statement-with-body stream body nil "get"))

;; set { ... }
(defprinter :set (&rest body)
  (print-statement-with-body stream body nil "set"))

;; return x;
(defprinter :return (expr)
  (format stream "return ~w;" expr))

;; argument
(defprinter :arg (type name)
  (format stream "~a ~a" type name))

;; constructor
(defprinter :constructor (name args &rest body)
  (print-statement-with-body stream body nil "~a(~@<~{~w~^, ~_~}~:>)" name args))

;; a = b;
(defprinter :setf (lvalue rvalue)
  (format stream "~w = ~w;" lvalue rvalue))

;; public class SomeClass { ... }
(defprinter :class (name &rest body)
  (print-statement-with-body stream body t "public class ~a" name))

;; namespace SomeNS { ... }
(defprinter :namespace (name &rest body)
  (print-statement-with-body stream body t "namespace ~a" name))

;; comment
(defprinter :comment (text)
  (format stream "// ~a" text))


Может быть, интересно взглянуть, во что разворачивается defprinter.
Ставим курсор в емаксе на последнюю закрывающуюся скобку и давим Ctrl-C Enter.

(PROGN (DEFUN PRINT-FORM-COMMENT (STREAM #:G288)
         (DESTRUCTURING-BIND (TEXT) (REST #:G288)
                             (FORMAT STREAM "// ~a" TEXT)))
       (SETF (GET ':COMMENT 'AST-FORM) 'PRINT-FORM-COMMENT))


Тут мы видим определение функции для разборки и печати узла
(комментария) и прицепление её к символу :comment (:comment, а не comment —
чтобы это был keyword, не привязанный к пакету — лисповому namespace'у)
через пропертю AST-FORM (здесь пропертя значит именованное значение,
привязанное к символу). #:G288 — сгенерированный (gensym) символ, гарантированно
не конфликтующий с другими именами из environment'а. Вместо
функции можно было бы использовать lambda, но это затруднило бы
отладку — функцию можно отTRACE'ить — после (trace print-form-comment)
в REPL будут выводиться все её вызовы с аргументами и возвращаемыми
значениями.

Следует отметить, что лисповские символы по умолчанию к регистру
не чувствительны (в связи с этим для простоты я решил использовать
строки вместо символов для названий C# пропертей и типов — хотя
проблема решается несложно). Большими буквами обычно выводится ответ Lisp'а.

Давайте ещё раз попробуем:
CL-USER> (p '(:namespace "MyTestNS"
          (:class "MyTestClass"
           (:field "int" "_someprop")
           (:constructor "MyTestClass" ((:arg "int" "someprop"))
        (:comment "This is a test")
        (:setf (:id "_someprop") (:id "someprop")))
           (:property "int" "SomeProp"
        (:get (:return (:id "_someprop")))
        (:set (:setf (:id "_someprop") (:id "value"))))
           (:property "int" "AnotherProp"
        (:get (:return 0))))))
namespace MyTestNS
{
    public class MyTestClass
    {
        private int _someprop;

        MyTestClass(int someprop)
        {
            // This is a test
            _someprop = someprop;
        }

        public int SomeProp
        {
            get
            {
                return _someprop;
            }
            set
            {
                _someprop = value;
            }
        }

        public int AnotherProp
        {
            get
            {
                return 0;
            }
        }
    }
}
NIL


Ну вот, теперь мы кажись могём из символьных выражений генерить C#.
И вроде как даже существенно удобоваримей того же CodeDOM всё выходит.
Ну, теперь дело за малым — делаем функцию-генератор AST на основе
декларативного описания:

;;; Data class generation

(defun generate-csharp-class (object)
  "Generate a C# class from DSL spec"
  (destructuring-bind (class-name . properties) (rest object)
    (loop for (nil prop-name prop-type) in properties
      for sharp-prop-name = (format nil "~:(~a~)" prop-name) ; C# property name
      for field-name = (concatenate 'string "_" prop-name) ; C# field name
      collect `(:arg ,prop-type ,prop-name) into init-args
      collect `(:setf (:id ,field-name) (:id ,prop-name)) into init
      nconc `((:field ,prop-type ,field-name)
          (:property ,prop-type ,sharp-prop-name
            (:get (:return (:id ,field-name)))
            (:set (:setf (:id ,field-name) (:id "value"))))) into props
      finally (return
            `(:class ,class-name
              (:constructor ,class-name ()
               (:comment "NOOP"))
              (:constructor ,class-name ,init-args
               ,@init)
              ,@props)))))

(defun generate-csharp-classes (data)
  "Generate C# classes from DSL spec"
  (destructuring-bind (ns-name . classes) (rest data)
    `(:namespace ,ns-name
      ,@(mapcar #'generate-csharp-class classes))))


generate-csharp-class генерит AST класса на основе
(object "Obj1" ...), а generate-csharp-classes генерит
всё вместе на основе (namespace "MyNS" ...):

;; глянем-ка на AST, интересно всё-таки

CL-USER> (generate-csharp-classes
      '(namespace "MyNS"
        (object "Obj1"
         (property "prop1" "int")
         (property "prop2" "string")
         (property "dblprop" "double"))
        (object "Obj2"
         (property "someprop" "object[]"))))
(:NAMESPACE "MyNS"
 (:CLASS "Obj1" (:CONSTRUCTOR "Obj1" NIL (:COMMENT "NOOP"))
  (:CONSTRUCTOR "Obj1"
   ((:ARG "int" "prop1") (:ARG "string" "prop2") (:ARG "double" "dblprop"))
   (:SETF (:ID "_prop1") (:ID "prop1")) (:SETF (:ID "_prop2") (:ID "prop2"))
   (:SETF (:ID "_dblprop") (:ID "dblprop")))
  (:FIELD "int" "_prop1")
  (:PROPERTY "int" "Prop1" (:GET (:RETURN (:ID "_prop1")))
   (:SET (:SETF (:ID "_prop1") (:ID "value"))))
  (:FIELD "string" "_prop2")
  (:PROPERTY "string" "Prop2" (:GET (:RETURN (:ID "_prop2")))
   (:SET (:SETF (:ID "_prop2") (:ID "value"))))
  (:FIELD "double" "_dblprop")
  (:PROPERTY "double" "Dblprop" (:GET (:RETURN (:ID "_dblprop")))
   (:SET (:SETF (:ID "_dblprop") (:ID "value")))))
 (:CLASS "Obj2" (:CONSTRUCTOR "Obj2" NIL (:COMMENT "NOOP"))
  (:CONSTRUCTOR "Obj2" ((:ARG "object[]" "someprop"))
   (:SETF (:ID "_someprop") (:ID "someprop")))
  (:FIELD "object[]" "_someprop")
  (:PROPERTY "object[]" "Someprop" (:GET (:RETURN (:ID "_someprop")))
   (:SET (:SETF (:ID "_someprop") (:ID "value"))))))

;; ну а теперь на шарп (* - последнее вёрнутое значение)

CL-USER> (p *)
namespace MyNS
{
    public class Obj1
    {
        Obj1()
        {
            // NOOP
        }

        Obj1(int prop1, string prop2, double dblprop)
        {
            _prop1 = prop1;
            _prop2 = prop2;
            _dblprop = dblprop;
        }

        private int _prop1;

        public int Prop1
        {
            get
            {
                return _prop1;
            }
            set
            {
                _prop1 = value;
            }
        }

        private string _prop2;

        public string Prop2
        {
            get
            {
                return _prop2;
            }
            set
            {
                _prop2 = value;
            }
        }

        private double _dblprop;

        public double Dblprop
        {
            get
            {
                return _dblprop;
            }
            set
            {
                _dblprop = value;
            }
        }
    }

    public class Obj2
    {
        Obj2()
        {
            // NOOP
        }

        Obj2(object[] someprop)
        {
            _someprop = someprop;
        }

        private object[] _someprop;

        public object[] Someprop
        {
            get
            {
                return _someprop;
            }
            set
            {
                _someprop = value;
            }
        }
    }
}
NIL

;; вуаля, блин!


У этого, понятное дело, может быть ещё куча применений —
можно генерить разные прокси классы, врапперы к базе/хранимкам и пр., в качестве источника
можно использовать .NET reflection напрямую через RDNZL, DBMS, можно парсить сырцы
через cl-yacc (в отличие от Yacc, препроцессинга он не требует, т.к. грамматика транслируется
макросами — отличный пример их применения, и отлаживается проще, т.к. есть TRACE) и т.д.
Короче говоря, R# на Лиспе написать куда как проще, чем на C#. Можно сделать мегакостыль для .NET.
Оговорка лишь одна — если можете писать на Лиспе, лучше пишите на Лиспе, это проще, чем
на C# с костылями, на чём бы эти костыли написаны не были. В общем и целом — ещё одно
замечательное применение Лиспа — dev tools.

Да, в исходнике я привёл ссылки на "вдохновителей", дублирую. Peter Norvig крут —
на таких, как он, Google держится PAIP читать ВСЕМ — хоть его в нашем краю
и достать не очень легко, оно того стоит — http://www.norvig.com/paip.html

;;;; Inspired by DPP (Dylan Pretty-Printer, a part of Peter Norvig's
;;;; Lisp to Dylan Converter — http://www.norvig.com/ltd/doc/ltd.html)
;;;; and by Dick Waters' paper "Some Useful Lisp Algorithms: Part 2"
;;;; (http://www.merl.com/publications/TR1993-017/)
;;;; See also: XP pretty-printer documentation in XP distribution
;;;; http://www-2.cs.cmu.edu/afs/cs.cmu.edu/project/ai-repository/ai/lang/lisp/code/io/xp/xp.tgz
Re[15]: Lisp
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 14.07.05 10:46
Оценка:
Здравствуйте, aka50, Вы писали:

A>Здравствуйте, eao197, Вы писали:


E>>Может быть удобства использования для средненького программиста, не желающего расширять сознание, а просто получающего зарплату за фиксированный объем работы в течении 40-ка часовой рабочей недели?


A>Ну опять о простых программерах. Простой программер тоже не шибко обрадуется на XSLT писать. ИМХО лисп проще.


Для перечисленных тобой вещей есть готовые инструменты, которые прячут всю эту сложность от программиста. В результате использование более сложных технологий оказывается проще.
... << RSDN@Home 1.1.4 stable rev. 510>>


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[3]: AST-based solution
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 14.07.05 10:47
Оценка:
Здравствуйте, fionbio, Вы писали:

F>
F>(namespace "MyNS"
F> (object "Obj1"
F>  (property "prop1" "int")
F>  (property "prop2" "string")
F>  (property "dblprop" "double"))
F> (object "Obj2"
F>  (property "someprop" "object[]")))
F>


F>Следует учесть, что символы namespace, object и property

F>данным генератором не используются и добавлены здесь для
F>читабельности.

Значит уже не годится — по причине того что эти символы должны проверяться, а любое отклонение детектироваться.
... << RSDN@Home 1.2.0 alpha rev. 565>>
AVK Blog
Re[16]: Lisp
От: aka50 Россия  
Дата: 14.07.05 10:48
Оценка:
Здравствуйте, eao197, Вы писали:

E>Для перечисленных тобой вещей есть готовые инструменты, которые прячут всю эту сложность от программиста. В результате использование более сложных технологий оказывается проще.


Сейчас конечно есть. Но в 1999 (или каком там XSLT родился) их не было. А лисп уже был. Зачем было изобретать? (вопрос риторический, можно не отвечать)
Re[4]: AST-based solution
От: fionbio  
Дата: 14.07.05 10:57
Оценка:
Здравствуйте, AndrewVK, Вы писали:

AVK>Здравствуйте, fionbio, Вы писали:


F>>
F>>(namespace "MyNS"
F>> (object "Obj1"
F>>  (property "prop1" "int")
F>>  (property "prop2" "string")
F>>  (property "dblprop" "double"))
F>> (object "Obj2"
F>>  (property "someprop" "object[]")))
F>>


F>>Следует учесть, что символы namespace, object и property

F>>данным генератором не используются и добавлены здесь для
F>>читабельности.

AVK>Значит уже не годится — по причине того что эти символы должны проверяться, а любое отклонение детектироваться.


Елки-палки, да пожалуйста:
;;; Data class generation

(defun generate-csharp-class (object)
  "Generate a C# class from DSL spec"
  (destructuring-bind (obj class-name . properties) object
    (assert (eq obj 'object) nil
        "malformed data, expected object: ~s" object)
    (loop for property in properties
      for (prop prop-name prop-type) = property
      for sharp-prop-name = (format nil "~:(~a~)" prop-name) ; C# property name
      for field-name = (concatenate 'string "_" prop-name) ; C# field name
      do (assert (eq prop 'property) nil
             "malformed data, expected property: ~s" property)
      collect `(:arg ,prop-type ,prop-name) into init-args
      collect `(:setf (:id ,field-name) (:id ,prop-name)) into init
      nconc `((:field ,prop-type ,field-name)
          (:property ,prop-type ,sharp-prop-name
            (:get (:return (:id ,field-name)))
            (:set (:setf (:id ,field-name) (:id "value"))))) into props
      finally (return
            `(:class ,class-name
              (:constructor ,class-name ()
               (:comment "NOOP"))
              (:constructor ,class-name ,init-args
               ,@init)
              ,@props)))))

(defun generate-csharp-classes (data)
  "Generate C# classes from DSL spec"
  (destructuring-bind (ns ns-name . classes) data
    (assert (eq ns 'namespace) nil
        "malformed data, expected namespace: ~s" data)
    `(:namespace ,ns-name
      ,@(mapcar #'generate-csharp-class classes))))


Можно ещё типы проверить, что там строки, где надо.
Я больше идею AST хотел продемонстрировать.
Re[17]: Lisp
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 14.07.05 10:58
Оценка: +1
Здравствуйте, aka50, Вы писали:

A>Здравствуйте, eao197, Вы писали:


E>>Для перечисленных тобой вещей есть готовые инструменты, которые прячут всю эту сложность от программиста. В результате использование более сложных технологий оказывается проще.


A>Сейчас конечно есть. Но в 1999 (или каком там XSLT родился) их не было. А лисп уже был. Зачем было изобретать? (вопрос риторический, можно не отвечать)


Так его можно еще более расширить. Но я обещал больше не спрашивать про причины непопулярности Lisp
(Кстати, когда я познакомился с языком Curl, я был поражен тем, что в нем документация по Curl-у была просто программами на Curl-е. Вообще, Curl -- это производная от Lisp-а. У них в альфа-версии даже арифметические операции записывались как в Lisp-е: {+ x y}. Затем, видимо в надежде сделать Curl более читабельным, арифметические операции стали записываться привычным образом: x + y).

Но вот посмотрев на примеры Lisp-овских программ, я, наверное, стал понимать, почему Lisp еще жив. Потому что некоторым товарищам он позволяет делать все, что они только захотят. Нужно отдать должное. У других языков запас возможностей поменьше будет.
... << RSDN@Home 1.1.4 stable rev. 510>>


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[4]: Lisp
От: cranky Украина  
Дата: 14.07.05 11:07
Оценка:
Здравствуйте, AndrewVK, Вы писали:

CP>>

CP>>(defparameter *test-desc*
CP>> '(:objects
CP>>   (:object :name "Obj1"
CP>>    (:property :name "prop1" :type "int")
CP>>    (:property :name "prop2" :type "string"))
CP>>   (:object :name "Obj2"
CP>>    (:property :name "foo10" :type "string")
CP>>    (:property :name "bar12" :type "sometype"))))

CP>>


AVK>Вопрос — насколько тщательно контролируется структура того, что ты привел?


Гм, а если так:
; Это автолисп
; проверено, работает

(setq objs
    '("objects"
        ("object" ("name" . "Obj1")
            ("property"
                (("name" . "prop1") ("type" . "int"))
                (("name" . "prop2") ("type" . "string"))
            )
        )
    )
)

(defun fun (lst)
    (if (= (car lst) "objects")
        (mapcar
            '(lambda (obj / name prop objpar)
                (cond
                    ((= (car obj) "object")
                        (setq
                            obj (cdr obj)
                            name (cdr (assoc "name" obj))
                            prop
                                (mapcar
                                    '(lambda (prp)
                                        (cons
                                            (cdr (assoc "type" prp))
                                            (cdr (assoc "name" prp))
                                        )
                                    )
                                    (cdr (assoc "property" obj))
                                )
                            objpar
                                (if prop
                                    (apply
                                        'strcat
                                        (mapcar
                                            '(lambda (prp) (strcat (car prp) " " (cdr prp) ", "))
                                            prop
                                        )
                                    )
                                    "__"
                                )
                            objpar (substr objpar 1 (- (strlen objpar) 2))
                        )
                        (princ (strcat
                            "public class " name "\n"
                            "{\n"
                            "\tpublic " name "(" objpar ")\n"
                            "\t{\n"
                            (apply
                                'strcat
                                (mapcar
                                    '(lambda (prp) (strcat "\t\t_" (cdr prp) " = " (cdr prp) ";\n"))
                                    prop
                                )
                            )
                            "\t}\n"
                            (apply
                                'strcat
                                (mapcar
                                    '(lambda (prp / typ nam)
                                        (setq typ (car prp) nam (cdr prp))
                                        (strcat
                                            "\tprivate " typ " _" nam ";\n"
                                            "\tpublic " typ " " (strcase (substr nam 1 1)) (substr nam 2) "\n"
                                            "\t{\n"
                                            "\t\tget { return _" nam "; }\n"
                                            "\t}\n"
                                        )
                                    )
                                    prop
                                )
                            )
                            "}\n"
                        ))
                    )
                )
            )
            (cdr lst)
        )
    )
    (princ)
)

(fun objs)
You aren't expected to absorb this
Re[5]: AST-based solution
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 14.07.05 11:08
Оценка:
Здравствуйте, fionbio, Вы писали:

F>Елки-палки, да пожалуйста:

F>
F>;;; Data class generation

F>(defun generate-csharp-class (object)
F>  "Generate a C# class from DSL spec"
F>  (destructuring-bind (obj class-name . properties) object
F>    (assert (eq obj 'object) nil
F>        "malformed data, expected object: ~s" object)
F>    (loop for property in properties
F>      for (prop prop-name prop-type) = property
F>      for sharp-prop-name = (format nil "~:(~a~)" prop-name) ; C# property name
F>      for field-name = (concatenate 'string "_" prop-name) ; C# field name
F>      do (assert (eq prop 'property) nil
F>             "malformed data, expected property: ~s" property)
F>      collect `(:arg ,prop-type ,prop-name) into init-args
F>      collect `(:setf (:id ,field-name) (:id ,prop-name)) into init
F>      nconc `((:field ,prop-type ,field-name)
F>          (:property ,prop-type ,sharp-prop-name
F>            (:get (:return (:id ,field-name)))
F>            (:set (:setf (:id ,field-name) (:id "value"))))) into props
F>      finally (return
F>            `(:class ,class-name
F>              (:constructor ,class-name ()
F>               (:comment "NOOP"))
F>              (:constructor ,class-name ,init-args
F>               ,@init)
F>              ,@props)))))

F>(defun generate-csharp-classes (data)
F>  "Generate C# classes from DSL spec"
F>  (destructuring-bind (ns ns-name . classes) data
F>    (assert (eq ns 'namespace) nil
F>        "malformed data, expected namespace: ~s" data)
F>    `(:namespace ,ns-name
F>      ,@(mapcar #'generate-csharp-class classes))))
F>


F>Можно ещё типы проверить, что там строки, где надо.


Можно. Только вот одна засада — жутко неудобно. Привести пример xsd, или на слово поверишь, что будет на порядок лаконичнее?
... << RSDN@Home 1.2.0 alpha rev. 565>>
AVK Blog
Re[6]: AST-based solution
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 14.07.05 11:11
Оценка:
Здравствуйте, AndrewVK, Вы писали:

AVK>Можно. Только вот одна засада — жутко неудобно. Привести пример xsd, или на слово поверишь, что будет на порядок лаконичнее?


Андрей, если не сложно, приведи -- мне интересно.
... << RSDN@Home 1.1.4 stable rev. 510>>


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[5]: Lisp
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 14.07.05 11:19
Оценка:
Здравствуйте, cranky, Вы писали:

AVK>>Вопрос — насколько тщательно контролируется структура того, что ты привел?


C>Гм, а если так:


Здорово, но я вобще то в лиспе не особо разбираюсь. Можно комментарии где и что и каким образом?
... << RSDN@Home 1.2.0 alpha rev. 565>>
AVK Blog
Re[6]: AST-based solution
От: fionbio  
Дата: 14.07.05 11:25
Оценка:
Здравствуйте, AndrewVK, Вы писали:

AVK>Здравствуйте, fionbio, Вы писали:


F>>Елки-палки, да пожалуйста:

F>>
F>>;;; Data class generation

F>>(defun generate-csharp-class (object)
F>>  "Generate a C# class from DSL spec"
F>>  (destructuring-bind (obj class-name . properties) object
F>>    (assert (eq obj 'object) nil
F>>        "malformed data, expected object: ~s" object)
F>>    (loop for property in properties
F>>      for (prop prop-name prop-type) = property
F>>      for sharp-prop-name = (format nil "~:(~a~)" prop-name) ; C# property name
F>>      for field-name = (concatenate 'string "_" prop-name) ; C# field name
F>>      do (assert (eq prop 'property) nil
F>>             "malformed data, expected property: ~s" property)
F>>      collect `(:arg ,prop-type ,prop-name) into init-args
F>>      collect `(:setf (:id ,field-name) (:id ,prop-name)) into init
F>>      nconc `((:field ,prop-type ,field-name)
F>>          (:property ,prop-type ,sharp-prop-name
F>>            (:get (:return (:id ,field-name)))
F>>            (:set (:setf (:id ,field-name) (:id "value"))))) into props
F>>      finally (return
F>>            `(:class ,class-name
F>>              (:constructor ,class-name ()
F>>               (:comment "NOOP"))
F>>              (:constructor ,class-name ,init-args
F>>               ,@init)
F>>              ,@props)))))

F>>(defun generate-csharp-classes (data)
F>>  "Generate C# classes from DSL spec"
F>>  (destructuring-bind (ns ns-name . classes) data
F>>    (assert (eq ns 'namespace) nil
F>>        "malformed data, expected namespace: ~s" data)
F>>    `(:namespace ,ns-name
F>>      ,@(mapcar #'generate-csharp-class classes))))
F>>


F>>Можно ещё типы проверить, что там строки, где надо.


AVK>Можно. Только вот одна засада — жутко неудобно.

AVK>Привести пример xsd, или на слово поверишь, что будет на порядок лаконичнее?

Верю, XSD себе представляю. Но. Во-первых, если проверку в Лиспе сделать
отдельно, она будет, понятное дело, короче. Обычно лично мне этого попросту не
требуется. Во-вторых, XSLT для генерации кода я когда-то сам использовать пытался
(см. Metaprogramming et al) и нашёл это крайне неудобным в силу чрезвычайной
ограниченности языка. XSLT логически являет собой своеобразный кастрированный
диалект Лиспа, беда только в том, что, простите, вместе с яйцами ему отхватили
голову (особенно это касается 1.0). В третьих, никто, блин, не мешает на входе
получать XML — его ж можно отпарсить в одну строчку через pxmlutils в sexpr,
а потом перевести в удобоваримый вид с практически нулевыми трудозатратами.
Re[6]: Lisp
От: cranky Украина  
Дата: 14.07.05 11:32
Оценка:
Здравствуйте, AndrewVK, Вы писали:

AVK>Здравствуйте, cranky, Вы писали:


AVK>>>Вопрос — насколько тщательно контролируется структура того, что ты привел?


C>>Гм, а если так:


AVK>Здорово, но я вобще то в лиспе не особо разбираюсь. Можно комментарии где и что и каким образом?


Вот:
(setq objs
    '("objects"
        ("object" ("name" . "Obj1")
            ("property"
                (("name" . "prop1") ("type" . "int"))
                (("name" . "prop2") ("type" . "string"))
            )
        )
    )
)

(defun fun (lst)
    ; здесь проверяется, что мы имеем именно список "objects"
    (if (= (car lst) "objects")
        (mapcar ; обработка объектов
            '(lambda (obj / name prop objpar)
                (cond
                    ; выбор вариантов по первому эл-ту, пока только "object"
                    ((= (car obj) "object")
                        (setq
                            obj (cdr obj)
                            name (cdr (assoc "name" obj)) ; имя объекта
                            prop
                                (mapcar ; обработка пропертей, и только их
                                    '(lambda (prp)
                                        (cons
                                            (cdr (assoc "type" prp))
                                            (cdr (assoc "name" prp))
                                        )
                                    )
                                    (cdr (assoc "property" obj))
                                )
                            objpar ; строка параметров конструктора
                                (if prop
                                    (apply
                                        'strcat
                                        (mapcar
                                            '(lambda (prp) (strcat (car prp) " " (cdr prp) ", "))
                                            prop
                                        )
                                    )
                                    "__" ; если нету свойств
                                )
                            objpar (substr objpar 1 (- (strlen objpar) 2))
                        )
                        (princ (strcat ; печать вывода одного класса
                            "public class " name "\n"
                            "{\n"
                            "\tpublic " name "(" objpar ")\n"
                            "\t{\n"
                            (apply
                                'strcat
                                (mapcar ; присваивания пропов в конструкторе
                                    '(lambda (prp) (strcat "\t\t_" (cdr prp) " = " (cdr prp) ";\n"))
                                    prop
                                )
                            )
                            "\t}\n"
                            (apply
                                'strcat
                                (mapcar ; объявления свойств и функций доступа к ним
                                    '(lambda (prp / typ nam)
                                        (setq typ (car prp) nam (cdr prp))
                                        (strcat
                                            "\tprivate " typ " _" nam ";\n"
                                            "\tpublic " typ " " (strcase (substr nam 1 1)) (substr nam 2) "\n"
                                            "\t{\n"
                                            "\t\tget { return _" nam "; }\n"
                                            "\t}\n"
                                        )
                                    )
                                    prop
                                )
                            )
                            "}\n"
                        ))
                    )
                )
            )
            (cdr lst)
        )
    )
    (princ)
)

(fun objs)
You aren't expected to absorb this
Re[8]: Lisp
От: Трурль  
Дата: 14.07.05 11:36
Оценка: 1 (1)
Здравствуйте, Cyberax, Вы писали:

C>А можно парсер Лиспа в 12 килобайт кода?


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