LINUX.ORG.RU

Лисп или Питон


0

4

Решил изучить новый язк программирования. Все думаю, чего лучше, лисп или питон. Цели - быстро делать мелкие поделки, небольшая гуйня, работа с субд типа скулайта, мускула, постгреса. Кто что подскажет, из знающих?

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

Кстати, SBCL - это не единственная реализация лиспа.

o_0 ?)

Вы переопределили стандартный macro-character #\' ? А как в этом случае будет работать чужой код в котором просто используют вот.такие.имена? Это выходит - вы нарушили стандарт?

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

Согласен. Решателям SLAE стоит взять какой-нибудь infix.lisp из репозитория CMU (а то добро пропадает) и поместить это дело под macro-character. А так, язык арифметики и булевой логики в обычных программах - редкость, всё больше пакеты/классы/специальные формы вроде определений верхнего уровня и прочих из consrol flow - там нет инфикса в принципе, везде префикс (как и в других языках).

Ура, хоть кто-то с кем-то иногда бывает согласен. Впрочем, инфикс - это дело десятое, на самом деле. Без него можно жить вполне.

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

> Я не лиспер, да. У меня нет скобкофилии.

И у меня вроде нет «скобкофилии» (я вообще С-синтаксис люблю), значит тоже не лиспер?

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

мне нужна технология редактирования кода в рантайме. В лиспе это делается легко и спокойно.

Неужели? И нажатие C-S-c - это тоже встроено в Лисп? Или всё же в SLIME?

не надо мне объяснять, что мне это не нужно, потому что я точно знаю, что мне это нужно и, более того, я этим постоянно пользуюсь в лиспе.

Я не собираюсь тебе объяснять, что тебе нужно. Человек, который пишет на смеси Delphi, SQL и CL, явно имеет очень сильные убеждения.

Итого: я не могу технологично отредактировать функцию в рантайме.

По-моему, ты хочешь на лету заменить код функции. Это не то, что делал пример на Tcl, автору которого я ответил.

Но ты правда этого хочешь? У функций есть атрибут func_code.

>>> def f(): print "Hello"
... 
>>> f()
Hello
>>> def new_f(): print "Welcome to hell"
... 
>>> f.func_code = new_f.func_code
>>> f()
Welcome to hell
>>> 

Добро пожаловать в ад.

И, я помню, вроде есть какая-то тонкость, отличающая def и присваивание.

Если она и есть, я ее не знаю.

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

Вы переопределили стандартный macro-character #\'

Я переопределил все constituent characters (всю латиницу и всю кириллицу), точку и ещё кучу всего. Почти всё переопределил.

В моей таблице чтения такой код работать не будет, и поэтому я сегодня полночи исправлял свой собственный код, который использовал такие.имена. И сегодня ещё поймал пару мест, где они встречаются. Их придётся заменить, как минимум, на |вот.такие.имена| Да, я нарушил стандарт, и об этом нисколько не сожалею. Чужие библиотеки я загружаю в их собственной таблице чтения. Зато теперь я могу написать, к примеру, так:

>(defun here-documentc-readmacro-reader (stream symbol)
  (declare (ignore symbol))
  (budden-tools:it-is-a-car-symbol-readmacro)
  (read-char stream)
  (let1 terminator (make-string 1 :initial-element (read-char stream))
    (setf terminator (or (CASE1::NATURAL-CLOSE-BOUNDARY terminator) 
                         terminator)
          )
    (text-up-to-terminator-lexer stream terminator)))

>(setf (symbol-readmacro (intern "HERE-DOCUMENT" :budden)) #'here-document-readmacro-reader)

> here-documentc (превед,
медвед)
"превед,
медвед"

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

> И у меня вроде нет «скобкофилии» (я вообще С-синтаксис люблю), значит тоже не лиспер?
Ты уже под подозрением.

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

<lisper-nazi>

;;; I get this WEED: ... where you get this WEED?
(defmacro my-let (var fun &body body)
  "Shortcut for (let ((a b)) . c) or (destructuring-bind a b . c)"
  (etypecase var
    (symbol `(let ((,var ,fun)) ,@body))
    (cons   `(destructuring-bind ,var ,fun ,@body))))
</lisper-nazi>

А как вы относитесь к отступам которые расставляет SLIME/Emacs? К тому что написано в good-lisp-style у Норвига с Питманом?

Кстати, в puri есть некий макрос if* там для ветви else нужно :else ставить.

Я не лиспер, да. У меня нет скобкофилии.

Есть такой Haskell, язык с невидимыми скобками )

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

Нет, вот серьёзно, я вообще часто не восторге от скобок, но такой синтаксис обеспечивает некоторые важные возможности и я его просто принял. И это мне кажется нормальным. Нормально принимать что-то, если ты получаешь адекватную компенсацию. Ведь идеала нет. Ты же со своим подходом отказываешься от возможности какой-либо интеграции с сообществом, что просто ужасно, на мой взгляд. Ради довольно мелочного (и на мой взгляд странного) удобства обрекать себя на одиночество... Ну, каждый решает за себя сам, конечно...

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

> Неужели? И нажатие C-S-c - это тоже встроено в Лисп? Или всё же в SLIME?
Какая разница? Если в Питоне подобное есть в рамках какой-то среды, то это было бы нормально (не считая остальных недостатков питона). Я не нашёл. Честно скажу, искал не слишком долго. Но сколько-то времени посвятил.

Это не то, что делал пример на Tcl, автору которого я ответил.

По-моему, это именно оно.

Но ты правда этого хочешь?

Да, я правда этого хочу. И не просто заменить, а: взять исходник, поменять в исходнике одну строку и заменить код на новый код, скомпилированный (или как там это в питоне называется) в том же контексте (в контексте того же модуля), что и старый исходник. В лиспе я это могу сделать хоть в командной строке, без среды, потому что в лиспе есть (in-package).

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

> А как вы относитесь к отступам которые расставляет SLIME/Emacs?
Я ими пользуюсь, потому что они автоматические. Привык.

К тому что написано в good-lisp-style у Норвига с Питманом?

Чукча не читатель. Я учил лисп по ctll2 (и до сих пор иногда открываю новые вещи, которых там не было).

Есть такой Haskell

не к ночи будь помянут.

Кстати, в puri есть некий макрос if* там для ветви else нужно :else ставить

Я вообще редко пользуюсь if. Потому что обычно там почему-то оказывается больше двух веток. И, чтобы не переделывать, сразу пишу cond.

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

Зато теперь я могу написать, к примеру, так

Не проще ли сразу сделать полный парсер над streams - такой как вам нужно, и my-load который бы загружал такие .mylisp файлы со специфичным кодом (тот парсер может вызывать родной CL-парсер в нужный момент на нужном коде). Т.е. вообще без задействования ридера - ридер скорее для небольших расширений, ретушей, чем для полного изменения синтаксиса.

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

Ты же со своим подходом отказываешься от возможности какой-либо интеграции с сообществом

Это тяжело, но переживабильно. Зато так я могу писать код быстрее и он будет более читаем (мной), чем чистый лисп.

Я считаю, нужно сделать разные скобки для разных частей предложения. Например,

(cond
 {условие1 код1}
 {условие2 код2}
 {условие3 код3}
 )
я, кстати, это уже могу сделать без особой боли, правда, не получится интегрировать библиотеки, которые тоже используют скобки. Но ведь в любом случае таких библиотек получится интегрировать не больше одной, а дальше будет конфликт и я лично в этот момент сделаю symbol-readmacro:
one-library[ бебебебебе]
another-library[ бебебеббе]
расплатой за это будет один пробел. Или так:
one-library:[бебебебе]
another-library:[бебебебебе]
но тут уже плохо может получиться, если ещё и пакет переключится. Вообще, это больная тема (как и всё, что связано с пакетами).

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

>> Это не то, что делал пример на Tcl, автору которого я ответил.

По-моему, это именно оно.

Напоминаю, «оно» работает и в Питоне. Там горячей замены кода не происходит, я гарантирую это.

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

> Не проще ли сразу сделать полный парсер
Тогда придётся и свою IDE делать. Боюсь, у меня маловато ресурсов для этого. Кроме того, мой код пока что всё ещё весьма хорошо совместим и переносим. Код, который реализует таблицу чтения, проверен (был в своё время) на четырёх реализациях. Это сейчас я уже начинаю отступать от переносимости в пользу вкусностей, но ещё не сильно отступил.

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

Не проще ли

Это к тому, что так по крайней мере решается проблема совместимости (раз), и это было бы выгодное расширение для скобкофагов (два)

;;; вот я пишу код с отступами
defpackage #:for-foo
  :use     #:cl
  :export  #:foo

in-package #:foo

defclass foo ()
  ;; но после открытой скобки начинается CL
  ((a ...)
   (b ...))

defmethod bar ((foo foo))
  ;; на правах парсера верхнего уровня
  ;; мы ведь ещё не открыли скобки
  foo.a + foo.b

;; если открыть её - будет ровным счётом ANSI CL.

В принципе не очень сложно сделать такое, для схематичной обрисовки форм верхнего уровня. Можно посмотреть как Franc Inc делала парсер в clpython (хотя там скорее всего излишек деталей).

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

> Там горячей замены кода не происходит, я гарантирую это.
Судя по примерам, я вижу обратное.

Напоминаю, «оно» работает и в Питоне.

Я не спорю, что «оно» работает. Т.е., в конкретике я ошибся. Но даже и в Дельфи «оно» работает. Тем не менее, в Питоне я пока не вижу технологии, о которой я сказал уже два раза. Взять исходник, поправить его и запендюрить. Так что - пока неприменимо на практике для целей инкрементной разработки/правки. В принципе, я не собираюсь пока переходить ни на Питон, ни на tcl, поэтому вопрос довольно академический. Хотя, если окажется, что для Питона такая технология есть, то это может в будущем что-то изменить для меня.

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

Я вообще редко пользуюсь if

Ну в любом случае для предикатов - довольно часто.

нужно сделать разные скобки для разных частей предложения

Зачем? Семантической нагрузки нет. И красивостей тоже особо никаких - я вот со своими шрифтами еле разглядел что там фигурная скобка, а не круглая :)

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

А вот здесь я скобкофил, потому что в EMACS я могу жонглировать целыми определениями, а тут не могу уже. Кроме того, лисп-мода будет полностью уничтожена, а этого не хочется. То, что я делаю, вносит минимальные повреждения в лисп-моду.

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

Да, круглая от фигурной и у меня почти неотличима. Значит, круглая и квадратная. Нужно затем, чтобы было за что глазу зацепиться. Типа, «а, это мы закрываем clause, а это - весь cond». ПРи большой глубине вложенности будет небезполезно.

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

>> Там горячей замены кода не происходит, я гарантирую это.

Судя по примерам, я вижу обратное.

В Питоне к старому имени просто привязывается новый объект-функция, замены кода существующего объекта не происходит. Впрочем, я это уже говорил.

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

А вот здесь я скобкофил

Ну ладно, тогда вам по сути нужен только ридер для символов который работает как обычно, но для 'a.b возвращает '(slot-value a 'b)? А для a.b.c - что?

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

> В Питоне к старому имени просто привязывается новый объект-функция, > замены кода существующего объекта не происходит. Впрочем, я это уже > говорил.
Мне, ессно, не нужна замена кода в существующем объекте, т.к. это означает почти неминуемый крах программы.

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

> Для a.b возвращает '(slot-value a 'b)
Нет, грубо говоря, a.b заменяется на (--> a b), где --> - некий макрос, который расширяется во время компиляции, если известен декларированные тип a, или во время выполнения, если он неизвестен.
Что делает этот макрос - зависит от типа a, можно запрогарммировать. Пока я сделал для структур, пакетов и строк:
строка.upcase = (string-upcase строка)
пакет.name = (package-name пакет)
структура.поле = (тип-структуры-поле структура)
Для объектов надо думать (см. выше).

И такой ридер мне не только нужен, он у меня уже есть.

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

если известен декларированные тип a, или во время выполнения, если он неизвестен

А как вы из portable-CL дотягиваетесь до такой информации?

Кстати, выше имелось в виду, что named-readtables это уже существующий пакет:

http://common-lisp.net/project/named-readtables

он позволяет использовать таблицы чтения так же как и пакеты - тем обеспечивая безопасность изменения ридера (и возможность изменять его независимо).

там так:

(require :named-readtables)

(defpackage #:my-super-package
  (:use     #:common-lisp
            #:named-readtables)
  (:export  #:my-super-syntax))

(in-package #:my-super-package)

(defun read-[]-like-list (stream char)
  (declare (ignore char))
  (read-delimited-list #\] stream))

(defreadtable my-super-syntax
  (:merge :standard)
  (:macro-char #\[ :dispatch)
  (:macro-char #\] :dispatch)
  (:macro-char #\[ #'read-[]-like-list))

и будут работать [] в cond:

(in-package #:cl-user)

(named-readtables:in-readtable my-super-package:my-super-syntax)

(cond
  [(numberp 1)   1]
  [(symbolp 'a) 'a])
;=> 1

правда, они и так будут работать:

[+ 1 2]
;=> 3

так как никакой семантической нагрузки тут нет.

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

Ещё мысли вслух - в стандарте есть такая штука, token, т.е. числа или символы - всё что написано «слитно». Символы могут содержать значки +/-/./и т.д., также сюда относится разбор a:b и a::b, ну и все хитрые способы записи чисел. Советую вам посмотреть на read-token в sbcl/src/code/reader.lisp (с кошерными GO :) так как вы по сути бродите вокруг именно этого и недовольны тем что при стандартизации было принято решение иметь в символах все эти точки плюсы слэши и т.п. как обычные элементы имени - по вашему a.b.c должно иметь особый смысл и превращаться в (--> (--> a b) c). Вот я честно говоря не знаю - если бы стандартизация проходила сейчас, то возможно что точечная запись и была бы принята (?). Например, a:b ведь имеет специальный смысл.

И в то же время - если вы берёте язык, CL, то вы также принимаете его стандарт, и пишете по стандарту. Если стандарт вас не устраивает - то вы (хм) не берёте такой язык :) Т.е. я всё же не понимаю стремления переделать стандартные вещи в деталях.

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

Чисто эстетически:

;;; cl:+
;;; is
(find-symbol "+" (find-package "CL"))

;;; ^ no problem

;;; foo.b
;;; is
(slot-value foo 'b)

;;; ^ ?

ну так повелось просто.

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

> А как вы из portable-CL дотягиваетесь до такой информации?
Никак. Это и есть первое отступление. Хотя есть переносимые code-walker-ы, но это надо перекрыть compile. Не хочу, потому что все они не поддерживают CL полностью. Разве только смотреть в реализации пакет walker или code-walker (а он там есть, устроен сходно в разных реализациях и компилятор, как я думаю, именно на нём и написан). В любом случае, риск кажется большим.

named-readtables это уже существующий пакет

Да, знаю, пользуюсь, я же написал. Вообще, наверное, я слишком туманно излагаю - чёто я заметил, что меня никто не понимает :-(

он позволяет использовать таблицы чтения так же как и пакеты

Не получится, потому что символов много, букв мало. Прочитайте ещё раз выше то, что я написал про symbol-readmacro - это и есть (по-моему, единственный разумный) выход. Ими пользуюсь уже около года.

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

Например, после нескольких попыток, пришёл к такой форме написания SQL-запросов:
[code]

(defvar *p-id* 234234151)

(fse * from product where id=::*p-id* ;


)
[/code]
для этого пришлось написать лексер (не парсер), понимающий SQL. Этот способ и будет использоваться вовеки веков, аминь.

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

Например, после нескольких попыток, пришёл к такой форме написания SQL-запросов:

>(defvar *p-id* 234234151)
>(fse * from product where id=::*p-id* ;
)
для этого пришлось написать лексер (не парсер), понимающий SQL. Этот способ и будет использоваться вовеки веков, аминь.

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

Разве только смотреть в реализации пакет walker или code-walker

Вот в SBCL такие вещи (т.е. трансформации с доступом к типам, чего не могут макросы) есть - deftransform и defoptimizer, их можно использовать и из пользовательского кода (пример выше с трансформатором для slot-value показателен). Т.е. walker там не используется - это что-то вроде user-driven-compiling-process, как-то так. Хотя walker тоже есть в pcl/walk.lisp, но для других целей.

Не получится, потому что символов много, букв мало.

Прочитайте ещё раз выше то, что я написал про symbol-readmacro

Не понял про это. Почему не получится? В одной таблице character имеет одну функцию чтения, в другой - другую, в третьей - вообще не диспетчеризируется. Переключение между таблицами осуществляется с помощью in-readtable.

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

для этого пришлось написать лексер (не парсер), понимающий SQL.

Но зачем? Когда такие вещи и так работают.

(select '* :from 'product
           :where [= [slot-value 'product 'id] *id*])

или

(sql (:select '* :from 'product :where (:= 'id *id*)))

почему столько внимания форме? Разве от того что одной скобкой станет - меньше что-то изменится?

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

Вот в Firebird можно делать идентификаторы из кириллицы. Но их надо заключать в двойные кавычки. По-моему, идиотизм. То отступление от стандарта, которое я делаю, гораздо меньше: идентификаторы с точками нужно заключать в ||. Повторюсь, библиотечный код можно загрузить в его собственной таблице чтения (copy-readtable nil) и этот код ничего не заметит. asdf позволяет это организовать. Т.е., разница будет только в том коде (новом), который будет зачитан в моей таблице чтения.

Что такое token, я знаю достаточно хорошо.

И вообще, то, что я делаю, полностью укладывается в стандарт CL. Могу я сделать свою readtable? Да. Могу придать иной смысл любой букве? Да. Стандарт это не запрещает. Любое изменение readtable меняет интерпретацию программ. Пока что единственное отступление от стандарта - это способ получить информацию о типе переменной. Но я склонен сказать, что следовало бы расширить стандарт и внести в него способы получить информацию о типе переменной переносимым образом. Я думаю, что это было бы совсем несложно. И даже было что-то такое, но потом исключили при стандартизации. (см. augment-environment в cltl2, который есть в некоторых реализациях).

Я сделал так, что некоторые символы, которые раньше читались просто, теперь читаются сложнее. Но за это я получил удобство, которое считаю ценным. Я взвесил плюсы и минусы, и решил, что овчинка стоит выделки. Я никого не принуждаю следовать за мной, но и моя свобода тоже остаётся у меня.

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

почему столько внимания форме? Разве от того что одной скобкой станет >- меньше что-то изменится?

Это я уже проходил и убедился в пагубности такого подхода. То, что ты привёл - это частный синтаксис, он не покрывает всего sql. Я пытался сделать свой и сделал довольно много (именно под firebird). Но то и дело наступал на грабли. То, что я сделал в итоге,хорошо тем, что это - в точности тот SQL, который описан в доке по firebird, без всяких дополнительных слоёв (которые содержат обычно грабли). Пример N1. Как ты будешь с помощью приведённого тобой языка хранимую процедуру? А вот как я это делаю:

(def-stored-procedure drun_kub_stroka_dokumentaSelect
 :doc "!Запускает куб, для отладки"
 :context 
 (proga
   (let-with-conc-type flds sql-rec
       (make-sql-rec 
        :fields 
        *kub_stroka_dokumenta_select-returns*))
   (define-procedure))
 :returns flds.declare
 :body (fbody
delete from gt_set_element;
insert into gt_set_element (number,ref_set) select id,1 from product where short_name containing 'зонтик и пер';
insert into gt_set_element (number,ref_set) values (::+фирма1+,10);
insert into gt_set_element (number,ref_set) values (::+фирма2+,10);
insert into gt_set_element (number,ref_set) values (M_IDOF(party,~~"Буржуй"),5); 
for select * from
   kub_stroka_dokumenta_select('2010-08-01','2010-10-31' --   (vp_dataNach simple_date)(vp_dataKon simple_date)
     ,10,0 --(ff_prdp_setId d_gt_set)(ff_prdp_iskluchaja int)
     ,1,0 --  (ff_prod_setId d_gt_set)(ff_prod_iskluchaja int)
     ,2,2 -- (ff_pstv_setId d_gt_set)(ff_pstv_iskluchaja int)
     ,3,2 -- (ff_gnr_setId d_gt_set)(ff_gnr_iskluchaja int)
     ,4,2 --(ff_pg_setId d_gt_set)(ff_pg_iskluchaja int)
     ,5,2 --(ff_kli_setId d_gt_set)(ff_kli_iskluchaja int)
     ) into ~~flds.pass do suspend;
   ^))

Как можно заметить, тело процедуры - это почти чистый firebird, с вставками из лиспа (и здесь как раз нужны те самые пресловутые точки, потому что иначе это почти сразу теряет смысл). Есть здесь и инфиксный вызов (M_IDOF, к-рый является макросом специально для SQL, он во время компиляции лезет в базу и выцепляет код объекта по его названию). С тех пор живу припеваючи. Имея возможность на практике сравнить то, что ты предлагаешь и то, что я делаю сейчас, я никогда не вернусь к тому, что ты предлагаешь. Для меня это пройденный, притом неудачный, этап.

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

И ты пойми, одно дело, когда ты что-то пробуешь, изучаешь. Другое дело - это реальная разработка на работе, когда тебе за день нужно выдать страницу кода и сделать ещё 50 запросов из командной строки. Любая лишняя, отвлекающая внимание или усложняющая работу мелочь начинает очень быстро бесить. Поэтому - в топку лишние слои.

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

Почему не получится? В одной таблице character имеет одну функцию
чтения, в другой - другую, в третьей - вообще не диспетчеризируется. > Переключение между таблицами осуществляется с помощью in-readtable.

Проблемы начнутся, когда ты захочешь комбинировать несколько таблиц чтения в одном файле исходника или в командной строке. Это возможно, но неудобно. А сливать таблицы чтения, подобно use-package - не получится, оптому что конфликт наверняка наступит очень быстро. Поэтому, мой принцип: один файл - одна таблица чтения, а в командной строке всегда одна и та же таблица чтения. При таких ограничениях не так легко жонглировать таблицами чтения, а если эти ограничения снять, начнутся грабли (проверено на личном опыте).

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

Как ты будешь с помощью приведённого тобой языка хранимую процедуру?

Просто отвечаю - не приходилось хранить CL код в базе (если об этом речь). В остальном, всё что можно в обычных SQL запросах, можно и в S-SQL.

А вот как я это делаю:

Ну, я примерно понимаю как вы это делаете - шаблонным образом вставляете результаты от CL кода в эту строку (в синтаксисе firebird) и потом этой строкой уже типичным образом осуществляется запрос к базе. Но тот же postmodern тоже имеет некий нижний или «сырой» уровень (строки запроса) в который компилируется запрос из синтаксиса s-выражений (sql macro). Т.е. да, есть некий DSL на s-выражений (S-SQL) который отображается в типичную строковую SQL форму. Для вас это лишний слой, который в топку, для пользователей postmodern - способ прозрачно сшивать концы из своего кода с запросами к базе при этом *оставаясь в рамках* (!) CL. Вы выходите за рамки CL с помощью ридеров, Clojure на вас нет - там макросов чтения нет :)

Другое дело - это реальная разработка на работе, когда тебе за день нужно выдать страницу кода и сделать ещё 50 запросов из командной строки. Любая лишняя, отвлекающая внимание или усложняющая работу мелочь начинает очень быстро бесить. Поэтому - в топку лишние слои.

Ну так а чем не устраивают существующие решения? Пока, кроме того что приходится писать немного более подробно и освящать какие-то места, не видно критики. Да, нужно писать полные аккесоры, или with-макросы, или настраивать аккессоры классов; запросы к базе пишутся в DSL на s-выражениях (тот или иной - у каждого биндинга).

Для меня эта многословность - что-то вроде основательности. Это не питон где зажимают детали так что не разберешься потом по месту, о чём тут речь :)

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

Что такое token, я знаю достаточно хорошо.

Понятно, что знаете. Я к тому что там read-token наглядный весьма.

А сливать таблицы чтения, подобно use-package - не получится

Это возможно, но неудобно.

Это естественно - как-то не очень хорошо сливать syntax:scheme и syntax:python (условно говоря), они несовместимы. А вот совместимые синтаксические таблица - можно объединять.

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

Гы ))))

И вправду Гы ) Ну не суть, если речь о процедурах SQL - какие там проблемы, непонятно.

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

>Я не собираюсь тебе объяснять, что тебе нужно. Человек, который пишет на смеси Delphi, SQL и CL, явно имеет очень сильные убеждения.
Скорее очень сильные повреждения[мозга](учитывая все, что он тут, и не только тут пытается доказать и выкладывает)

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

Нет, на самом деле.

С den73 не имеет смысла вести дискуссию о CL - он совершенно непонятно на какой хрен CL использует, потому что ни одним из реальных преимуществ CL он не пользуется, и все что он пытается сделать уже хрен знает сколько лет(я вот уже два года насчитал) - это сделать из CL - Дельфи{*}. Это, во-первых, непонятно на какой хер нужно, и, во-вторых, по-хорошему, достойно прописывания рецепта на нейролептики. Я на полном серьезе сейчас говорю.

По поводу «не пользуется преимуществами» надо дать комментарий:
CLOS он отвергает - «тормозит» видите ли.

Я очень сильно сомневаюсь, что он реально сталкивался(что он не писал его - понятно, естественно, так как он отвергает CLOS) с кодом на CL который бы неприемлимо тормозил, и в котором бы основным боттлнеком был бы CLOS.

Нет, естественно, если к примеру, писать какой-нибудь реалтайм рендерер(тридэдвижок), и использовать там в качестве примитивных структур данных(вектора, точки и т.п.) CLOS-объекты, то оно будет неприемлимо тормозить.

Но, во-первых, я, лично, никогда идиотов, подобный код пишущих, не видел, а во-вторых - den73 пишет не 3d движок, и, вообще, судя по всему, пишет приложение совершенно не того класса, который бы требовал подобного внимания к производительности.

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

Насколько я вижу по выкладкам его кода и по его рассуждениям, макросы он тупо абьюзит, используя исключительно для {*}

Код на CL, правильно использующий макросы(да и не только макросы, вообще говоря, а и CLOS, и даже обычные функции), вообще практически не имеет необходимости вручную обращаться к полям структур. Это низкоуровневая деталь, которую принято скрывать за разными абстракциями. Неумение и/или нежелание den73 строить адекватные абстракции также выдает его постоянное нытье о количестве скобок; например, в том же операторе let. Потому что для того, чтобы вот ЭТО стало проблемой, код должен представлять из себя невероятную копипасту из однотипных действий(т.н. «китайский код»).

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

> С den73 не имеет смысла вести дискуссию о CL - он совершенно

непонятно на какой хрен CL использует, потому что ни одним из

реальных преимуществ CL он не пользуется



Как же, он использует возможности интерактивной разработки, и это очень много, но поскольку ты SLIME не используешь, то и оценить не можешь ;)

Ну и вообще да, он понял CL не так как ты, многоликий такой язык. Но, не пролистав хотя бы пару тысяч строк реального кода, я бы поостерёгся делать подобные выводы.

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

>Как же, он использует возможности интерактивной разработки, и это очень много, но поскольку ты SLIME не используешь, то и оценить не можешь ;)

В процитированном абзаце гораздо более значима вторая его часть, которую ты цитировать не стал:

все что он пытается сделать уже хрен знает сколько лет(я вот уже два года насчитал) - это сделать из CL - Дельфи{*}. Это, во-первых, непонятно на какой хер нужно, и, во-вторых, по-хорошему, достойно прописывания рецепта на нейролептики.

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

В, общем, Love5an, ты прошел свои полшага. Из заигноренного состояния, видимо, тебе будет легче бороться со мной - врагом CL. Впрочем, глядя на тебя, любой нормальный человек уже задумается, а не вреден ли лисп для психики. Прощай.

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

не приходилось хранить CL код в базе (если об этом речь)

Нет, не об этом. Вот о чём: http://www.ibase.ru/devinfo/sp_call.htm

Основная и, на практике, фатальная неприятность с твоим подходом - вот какая. Ты написал SQL запрос на 50 строк (а реально такие запросы бывают, и нередко). Где-то в нём есть ошибка. Ты скормил свой текст с ошибкой базе данных и она вернула: ошибка в строке 33, позиции 28. Как ты будешь искать это место в S-SQL? Как Шерлок Холмс, методом дедукции? Так ты много не заработаешь. А fbody умеет находить это место автоматически.

Вы выходите за рамки CL с помощью ридеров

Я не поменял ни одной строчки в реализации CL, и весь код fbody - это переносимый CL. Лежащий в его основе механизм symbol-readmacro я проверял на 4 реализациях точно, а может, и на 5. Так что код, который я привёл - это CL, если он выходит за рамки чьих-то привычек, то... видимо, это были вредные привычки :P

Для вас это лишний слой, который в топку, для пользователей postmodern - способ прозрачно сшивать концы из своего кода с запросами

Он не лишний. У меня он тоже есть, причём, не только для SQL, а для нескольких языков, я им пользуюсь и собираюсь пользоваться дальше. Просто он менее удобен, чем вариант, основанный на лексере (хотя бы по той же причине невозможность отследить место ошибки). И поэтому он у меня не нижний, а боковой.

> (with-formatter-stack case1:*c-formatter* (pd `(:l a = b + 'c)))
A = B + "C"
T

> (with-formatter-stack case1:*pascal* (pd `(:l a = b + 'c)))
A = B + 'C'
Ещё год назад fbody не было и я вынужден был всё писать через этот слой. Быстро стало ясно, что sql код намного быстрее проще писать просто руками, складывая строки. Или вообще не используя лисп. Спасло лисп только то, что это был конвертер базы данных, который над не писать, а генерировать из метаданных. Хотя, на самом деле, серверные языки хранимых процедур тоже поддерживают МП, там есть eval, а генерировать код всегда можно конкатенацией строк. Правда, в firebird есть ограничение на размер строки для eval, и там есть ещё недостатки у языка хранимых процедур. Если бы это был MS SQL, я, скорее всего в этот момент отказался бы от лиспа. Когда я написал fbody, я вздохнул с облегчением и с тех пор меня не тошнит от необходимости написать запрос или хранимую процедуру. Когда я теперь захожу в код, написанный с помощью этого старого слоя, мне становится жутко, потому что он очень хрупок, плохо читаем и его трудно отладить.

Пока, кроме того что приходится писать немного более подробно и освящать какие-то места, не видно критики. Да, нужно писать полные аккесоры, или with-макросы, или настраивать аккессоры классов; запросы к базе пишутся в DSL на s-выражениях (тот или иной - каждого биндинга).

Производительностью моего труда. Я же не ради эстетства сижу за компьютером, а чтобы деньги зарабатывать. Идеи DSL на s-выражениях красивы на первый взгляд и меня они тоже поначалу очаровали. Но они сливают, когда этим приходится пользоваться каждый день. Аналогичная ситуация, кстати, с javascript. Была (и ещё есть вроде) какая-то библиотека для генерирования javascript из s-выражений. В итоге, её автор в переписке (не со мной) вроде бы признал, что это была дурная идея. Например, в javascript используется и одинарная, и двойная кавычки для ограничения строк, а в лиспе - только двойная. Как это правильно выразить в твоём DSL? Кстати, в firebird тоже используются двойные кавычки. И, вообще, fbody - это тоже DSL, только со своим лексером.

> '(fbody select ::(+ 2 2) from dual^)
(BUDDEN-TOOLS::L/WITH-OUTPUT-TO-STRING (META-PARSE-FIREBIRD::SS)
  (BUDDEN-TOOLS::L/PRINC (BUDDEN-TOOLS::L/RORL " select " '(NIL 1099114 1099122)) META-PARSE-FIREBIRD::SS)
  (BUDDEN-TOOLS::L/PRINC (BUDDEN-TOOLS::L/RORL (X-TO-INLINE-SQL (+ 2 2)) '(NIL 1099122 1099130))
                         META-PARSE-FIREBIRD::SS)
  (BUDDEN-TOOLS::L/PRINC (BUDDEN-TOOLS::L/RORL " from dual" '(NIL 1099130 1099141))
                         META-PARSE-FIREBIRD::SS))

В нём есть два способа подстановки выражений из лиспа, через :: и через ~~ (может, их надо свести в один, но пока и так сойдёт). Т.е., я тоже могу управляемо генерировать SQL из лиспа. Также есть механизм макрорасширений для SQL:

> (def-firebird-macro-1 M_REC_CNT (s) (fbody count(*) from ~~s tbl^))
M_REC_CNT

> setf *firebird-trace* t
T

> fse M_REC_CNT(product);
select   count(*) from product tbl
((152631))
#("COUNT")
Можно было бы просто подставить результат выполнения функции на лиспе
                                                                
> defun m-rec-cnt (s) (fbody count(*) from ~~s tbl^)
m-rec-cnt
> fse ~~(m-rec-cnt "product");
, но количество появляющихся при этом лишних сбивающих с толку значков в тексте достаточно велико, чтобы специализированный механизм макросов был оправдан.

А тем временем я, благодаря тебе, засомневался, правильно ли я выбрал букву для a.b.c, может, надо было другую букву задать? Только не знаю, какую. Можно a^b^с. У кого сколько выдаёт апропос на "." и на «^»? У меня разница примерно в 10 раз (точки больше, естественно), причём, почти все упоминания ^ - мои, а упоминания "." исходят из многих мест.

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

> Lython же!
Чёто я не понимаю смысла. Нахрена транслировать лисп (который умеет компилироваться в натив) в тормозной байткод? Чтобы лучше тормозил? Я, на самом деле, думаю, что при желании наверняка можно сделать в Питоне такую штуку с переопределением в том же контексте, надо только разобраться, как.

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

Оказывается, от Love5an пошла большая ветка дискуссии, и нельзя пока его заигнорить. Ничего, заигнорим чуть погодя.

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

Нет, не об этом.

Да, я уже понял.

Ты скормил свой текст с ошибкой базе данных и она вернула: ошибка в строке 33, позиции 28. Как ты будешь искать это место в S-SQL?

Я нажму на shortcut в SLIME и посмотрю в открывшемся буфере как выглядит выражение S-SQL в строковом представлении (про которое и вернулась ошибка). Вы, наверно, скажите что это драгоценные секунды, которые деньги ;)

Но вообще у меня возникло противоположное впечатление от использования S-SQL. В одной книжке (Code Complement) есть такая табличка - там самые распостранённые языки (C, C++, Java и т.д.) сравниваются по уровню абстрактности в сравнении с Си, так вот SQL там занимает самое высокое место - 10 к 1 в сравнении с Си. Это очень декларативный язык, если возможны ошибки в S-SQL то трёх видов - неправильно расставлены скобки, использованы неправильные операторы или опрераторы расставлены семантически не в том порядке. Первое можно исключить из рассмотрения (не смешно и есть автозавершение в SLIME), во втором случае использования неправильных операторов выражение просто не скомпилируется из s-выражений в строковое представление. Остаются только семантические ошибки. Я хочу сказать, что если писать в родном нерегулярном синтаксисе, то можно чего-то забыть и будет синтаксическая ошибка, в случае же s-выражений пишется сразу валидный код который всегда компилируется в валидное представление, так что можно ошибится только в семантике (например предикаты фильтрации расставить не в том порядке), но эти ошибки уже немного из другой оперы. Это вообще свойство языков на s-выражениях - мы скорее ошибёмся в семантике, чем напишем что-то синтаксически неправильно. Часть семантических ошибок (как использование не тех операторов или неправильное использование специальных форм / макросов) видны ещё при компиляции, оставшаяся часть - это ошибки в логике.

Была (и ещё есть вроде) какая-то библиотека для генерирования javascript из s-выражений. В итоге, её автор в переписке (не со мной) вроде бы признал, что это была дурная идея.

Вроде? Если речь про parenscript, то судя по блогу автора, по форкам и по использованию в других проектах эта библиотека по-прежднему востребована.

Производительностью моего труда.

Сойдёмся на том, что это основной критерий. Касательно инфраструктуры других языков вокруг CL, т.е. связок с HTML, JavaScript или SQL всегда было два подхода - язык на s-выражениях который компилируется в target представление (cl-who -> HTML, parenscript -> JavaScript). И подход шаблонов когда всё наоборот - используется target язык, но в нём шаблонным образом расставлены связки с lisp-side (как у вас в fbody :: и ~~), как пример - cl-closure-templates (который, кстати, может использовать ту самую parenscript в качестве js backend-а). Соответсвенно - то или другое это вопрос удобства.

А тем временем я, благодаря тебе, засомневался, правильно ли я выбрал букву для a.b.c, может, надо было другую букву задать?

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

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

> Вы, наверно, скажите что это драгоценные секунды, которые деньги ;)

Это - секунды только в самых простых случаях. Обычно это будут десятки секунд, потому что потом надо будет отлистать к тому месту, откуда сгенерён данный текст. Не факт, что компилятор лиспа укажет это место достаточно точно.

Это очень декларативный язык, если возможны ошибки в S-SQL то трёх

видов - неправильно расставлены скобки, использованы неправильные


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



Ты как-то очень быстро заменил SQL на S-SQL. SQL - действительно очень высокоуровневый язык, а вот добавляет ли к его уровню что-то префикс «S-» - вопрос открытый.

Названный тобой перечень ошибок явно не полон и ошибки типа «неверный идентификатор» из него исключены зря. Они встречаются весьма часто. Наличие автозавершения не гарантирует от них, если ты веберешь не то завершение из возможных. Чтобы полностью защититься от них и выдать их все до момента генерации SQL, данная оболочка вокруг SQL должна в совершенстве знать данный диалект SQL и понимать все нюансы преобразования пространств имён в SQL запросе при использовании псевдонимов полей, псевдонимов таблиц, вложенных запросов (select * from (select ... ) foo), иметь полный доступ к метаданным (select * from stored_procedure), понимать определения view (как минимум, перечень полей должна знать), а это недёшево с точки зрения производительности и удобства работы, поскольку метаданные могут меняться на ходу. И это сложно реализовать. Честно сказать, я не верю, что в твоей библиотеке это реализовано полностью и надёжно для какого-либо сервера. И даже, если реализовано, ты получаешь ошибку на секунду раньше меня, но в более неудобной для поиска форме. Так что же ты выиграл в итоге?

в своей named-readtable в которую (во избежания конфликтов) нужно просто переключатся


Я не сторонник переключений, это неудобно. Лучше, пожалуй, переделаю на ^, пока этот код a.b ещё не размножился слишком сильно. Хотя надо ещё подумать.

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