>Раз уж зашла такая речь, может еще подскажете стандартные аналоги Lex/Yacc для Lisp? Я понимаю, что налабать свой собственный транслятор с нуля на Lisp -- самое оно для "настоящих мущин". Но хотелось бы без особого геморроя и, по возможности, в рамках известной технологии.
Без проблем. Причем генерация всяких LALR, LR и пр. парсеров -- это задача красивейшим образом решаемая на LISP без отсылки к другим средствам. Если для C Lex, Yacc -- это внешние костыли, то в LISP парсинг делается без отсыла куда-либо еще. Сам генератор парсеров сделан на LISP, грамматика описывается на LISP, лексические формы описываются на LISP, и генерируется готовая LISP-программа парсера по твоей грамматике.
>Именно это и погубило его в моих глазах. А как фанател от него в свое время...
А чего в нем страшного? В виндах, насколько я знаю, он выглядит неотличимо от нативного интерфейса. В Маках тоже использует их кнопочки. а в Linux вот чего ребята тут демонстрировали:
Они пишут, что это какая-то тестовая ветка Tk8.5a3. Выглядит очень прилично. Думаю, что будет красиво. Да и некрасивый Tk можно красиво оформить. Главное -- это вкус иметь :)
> А можно поинтересоваться: Лисп -- это единственный грамотно сконструированный язык?
ИМХО нет. Например я считаю достаточно грамотно сконструированной жабу, но предпосылки, заложенные в ней (примитивность и ограничения), мне не нравятся. С также достаточно хорош для свох задач, имеет минимум "роялей в кустах", хотя ещё есть куда, но весьма низкоуровнев, увы. С++ наоборот неудачен.
Вообще, ИМХО попытки сочетать традиционные разделения на примитивные типы (целое, вещественное итд) и обекты и затем использовать для операций с частью из них традиционные записи операторов, инфиксные +-*/ совместно с функциями, а для объектов функции - корявое и неудачное. Создатели лиспа сделали смелый шаг - отказались от традиционных нотаций, которые в программировании неудобны. Из-за чего появился хороший язык, и кучя народу, которому он не нравицо из-за непривычности.
Ладно, напишу. Однако два clg я знаю, древний для гтк1 и второй, clg-0.9... Который пашет с гтк2. Насколько я помню, clg неработает с clisp. Нужен cmucl которое я юзаю или sbcl.
> Они пишут, что это какая-то тестовая ветка Tk8.5a3.
Три года назад он все еще выглядел кошмарно. А в прошлом году я уже успел присесть плотно на gtk. И не вижу причин отказываться от него. Только, пожалуйста, без флейма. Просто сейчас это мой выбор.
И это радует. Для меня Лисп прошел сугубо по касательной. А функциональную парадигму я изучал по айверсоновскому APL/J. Об этом языке тоже ходили легенды. Например, что модель ядра OS/360 может быть записана на этом языке в 120 символов ;-). Сам я этого не видел, зато сам написал программу поиска простых чисел в 17 символов и решение задачи о 8 ферзях где-то в десяток строк. Хотя у товарища на прологе все-равно получилось короче :-(. Я даже умудрялся писать на этом языке неплохие инструментальные штучки, с SQL-биндингдами к Access и обработкой текста. А потом бросил.
Примерно тогда мы с товарищами сошлись во мнении, что любой алгоритм имеет фиксированную информационную емкость, а его запись на различных языках отличается только уровнем энтропии. Отсюда следствие, что на написание любой программы определенной сложности необходимо примерно одно и то же время. Различается только способ разработки. В "низкоуровневых" языках (то есть, с высокой энтропией, или, как любят здесь говорить, "быдлоязыки"), мысль разворачивается согласно канонам классической литературы: экспозиция, завязка, кульминация, развязка. Такой стиль близок большинству людей, поэтому эти языки популярны. А вот в "высокоуровневых" языках (с низкой энтропией) мысль может быть выражена весьма четко и ясно, фактически, с лапидарностью афоризма. Тут само решение рождается с помощью некого "мысленного скачка", когда автор долго думает, а потом программа рождается, как будто из ничего. Это, конечно же, завораживает, и не может не привлекать. Однако, Вы можете представить себе человека, который говорит исключительно афоризмами? Вот и получается, что в любом, даже самом функциональном языке, есть куски императивной парадигмы, чтобы хоть как-то дать разработчику костыли для привычного мышления. Что-то вроде строительных лесов. И Лисп, насколько я знаю, тут не исключение -- кроме рекурсии в нем есть и циклы и ветвления. Другое дело, что это считается моветоном, и в законченной программе должно быть устранено. А вот за что мне нравится Питон, так это за то, что в нем, начав писать императивно, несложно отрефакторить окончательное решение в чисто функциональном стиле.
> Создатели лиспа сделали смелый шаг - отказались от традиционных нотаций, которые в программировании неудобны.
Вообще-то они еще не были традиционными _в программировании_ (программирования как профессии еще практически не существовало). А против нотации Лиспа люди "проголосовали ногами".
Я не совсем понял что тебя так удивляет или расстраивает. Ну, за исключением того что банан вкуснее лиспа.
> Отсюда следствие, что на написание любой программы определенной сложности необходимо примерно одно и то же время.
Это неправильное следствие. В какой-то степени. Потому что одна и та же задачя, выраженная в одних терминах, решается легче, чем выраженная в других терминах. Я приводил примеры - нахождение множества всех перестановок и доступ к бд. Если решать чисто низкоуровневым способом - при помощи циклов, получится конкретная бяка. С помощю контейнеров, предоставляемых С++, уже намного легче. Питольим способом - с рекурсиями и возможностью выделения подпоследовательностей - наименее сложный из низкоуровневых вариантов. А вот лисп - предоставляет возможность описания терминов и оперирования ими, из-за чего для решения задачи можно использовать наиболее оптимальную терминологию, без привлечения лишних сущностей, каковыми в моём примере являются индексы элементов. Таким образом, если задачу ослободить от ненужной шелухи, конечно, она может решиться намного быстрее и проще.
> В "низкоуровневых" языках (то есть, с высокой энтропией, или, как любят здесь говорить, "быдлоязыки"),
Ты всё напутал. "быдлоязыками" тут называют низкокачественные наречия, которые _неоправданно_ широко используются по безграмотности, независимо от их уровня. Самый низкоуровневый из массовых - С, но я ни разу не видел чтобы ево называли "быдлоязык".
> Вот и получается, что в любом, даже самом функциональном языке, есть куски императивной парадигмы, чтобы хоть как-то дать разработчику костыли для привычного мышления.
Не совсем так. Просто ряд действий, например ввод-вывод, принципиально не описываются адекватно в функциональном стиле.
> И Лисп, насколько я знаю, тут не исключение -- кроме рекурсии в нем есть и циклы и ветвления. Другое дело, что это считается моветоном, и в законченной программе должно быть устранено.
Тоже не совсем так. Моветоном считается зряшное использование "деструктивных" действий, которые имеют побочные эффекты. Как раз из-за того, что злоупотребление ими чревато своими последствиям. В тех случяях, когда это нужно и полезно, такая возможность есь и ей можно пользоваться. Другое дело, что это бывает крайне редко, и их использование зачастую (не всегда!) говорит о недостаточной квалификации разработчика.
> Если решать чисто низкоуровневым способом - при помощи циклов, получится конкретная бяка.
Зато эту бяку проще развернуть во времени, что более естественно для человеческого мышления. В функциональном подходе это тоже можно сделать с помощью серии последовательных приближений, но каждый раз это будет "решение целиком", то есть, преодоление "смыслового разрыва" одним скачком. Это не до всех доходит. Лично я всегда вначале выписываю цикл, а потом сворачиваю его в функциональный вызов. То есть, преодолеваю ту же пропасть в два шага. Грубо говоря, есть также подозрение, что процедурная декомпозиция намного более естественна, чем функциональная. Правда, меня можно обвинить в том, что я не крутой перец. С другой стороны, а почему бы мне не предположить, что Вы делаете то же самое, только прячете от меня промежуточные результаты?
Кстати, а как обстоит дело с пошаговой отладкой в Лисп-средах? То есть, я догадываюсь, что она, скорее всего, не нужна. Однако, я подозреваю, что в практической жизни человек все же чаще мыслит алгоритмически, "шаг за шагом", а функции использует только для оптимизации. Так проще. Отсюда и более высокая популярность императивных языков.
> А вот лисп - предоставляет возможность описания терминов и оперирования ими, из-за чего для решения задачи можно использовать наиболее оптимальную терминологию, без привлечения лишних сущностей, каковыми в моём примере являются индексы элементов. Таким образом, если задачу ослободить от ненужной шелухи, конечно, она может решиться намного быстрее и проще.
На самом деле, Вы просто умело прячете эту шелуху "под коврик". А выработка "оптимальной терминологии" -- не более, чем разработка "оптимальной библиотеки/фреймворка" в императивных языках. Вот и получается, что все то время, пока Вы придумываете "оптимальную терминологию", вполне можно успеть изготовить приличную императивную штуку, решающую поставленную задачу. Это я и имел ввиду, когда говорил об "информационной емкости". То есть, пока одни думают, другие пилят. Иногда выигрывают одни, иногда другие -- это зависит от степени фанатизма (помните "Записки жены программиста"? ;-). В среднем же получается паритет, что и было выражено в виде гипотезы.
Правда, это все не касается возможностей повторного использования кода. Создание "оптимальной терминологии" позволяет эффективно повторно использовать код. Так же, как и написание качественной библиотеки. Однако, создать уникальную библиотеку для уникальной задачи, а потом вычесть из общего времени решения создание библиотеки -- это, согласитесь, передергивание. У нас в таких случаях обычно вспоминают знаменитое "Лучше день потерять, но потом за пять минут долететь" ;-).
> Зато эту бяку проще развернуть во времени, что более естественно для человеческого мышления.
> Лично я всегда вначале выписываю цикл, а потом сворачиваю его в функциональный вызов.
Попробуй перестановки наборов произвольной длины, без контейнеров и рекурсий, только циклами. Результат сюды пожалста.
> С другой стороны, а почему бы мне не предположить, что Вы делаете то же самое, только прячете от меня промежуточные результаты?
здравая мысль. Как говаривал один извесный философ, откуда нам знать что стулья не корчат нам рожи когда мы отворачиваемся и не смотрим на них?
> Кстати, а как обстоит дело с пошаговой отладкой в Лисп-средах?
Весьма неплохо. Есть трассировка и ещё всякое.
> На самом деле, Вы просто умело прячете эту шелуху "под коврик".
Тут мы вступили на зыбкую почву предположений и догадок. Предлагаю вернуться к этому вопросу когда предоставите код для перестановок чисто императивными методами.
> Если для C Lex, Yacc -- это внешние костыли, то в LISP парсинг делается без отсыла куда-либо еще. Сам генератор парсеров сделан на LISP, грамматика описывается на LISP, лексические формы описываются на LISP
То есть "внешнекостыльность" Lex и Yacc проявляется в том, лексемы описываются как регулярные выражения, а грамматика описывается не на Си, а как БНФ ?
> Попробуй перестановки наборов произвольной длины, без контейнеров и рекурсий, только циклами. Результат сюды пожалста.
Самое смешное, что мы решали эту задачку на олимпиадных сборах по информатике еще в лохматом 1988 году ;-). Сейчас уже и не вспомню суть, но, кажется, решения было чисто императивным, писали мы его на РАЯ ;-). Помню только, что решение было изящным и остроумным, я потом по блату раздавал знакомым в институте. Почему, собственно, меня и заинтриговал пример. Впрочем, могу и ошибаться. Попробую вечером добраться до своих школьных тетрадок, посмотрю.
Кстати, если Вам еще не надоело, то раз уж зашла речь о рекурсиях, то вот еще один вопрос: какую глубину выдерживает вычисление функции Аккермана, ну, например, в Common-Лиспе? В принципе, интерпретатор у меня есть. Можете написать здесь корректное решение?
Вообще говоря, в подавляющем большинстве случаев рекурсия нормально заменяется циклами. Взять хотя бы такую задачку. Функция f(n) для целых неотрцательных n определена так: f(0)=0, f(1)=1, f(2n)=f(n), f(2n+1)=f(n)+f(n+1). Для данного N найти и напечатать f(N). Обязательное услове: N столь велико, что недопустимо заводить массив, длина которого растет с ростом числа N).
Задачу нужно было решить на Фортран-77, где принципиально нет рекурсии. А дополнительное условие специально запрещало создавать стек. Я долго не мог решить ее именно в таком виде. И решил на удивление быстро в рамках исчисления Дийкстры: самым сложным оказалось найти подходящий инвариант. Поверьте, кайфу было не меньше, чем от перестановок на Лиспе!
О! Сейчас посмотрел в условия олимпиады 1980 года, там оказывается есть Ваша задача! Вот ядро решения на Паскале:
for i:=m-1 downto 1 do if (P[i]<P[i+1]) then begin n:=P[i]; for j:=m downto i do if (n<P[j]) then begin P[i]:=P[j];P[j]:=n; k:=1; while i+k<m-k+1 do begin n:=P[i+k]; P[i+k]:=P[m+1-k]; P[m+1-k]:=n; k:=k+1; end; j:=i; end;
Достаточно длинно, не спорю, целых 17 строк. На C короче -- ядро уместилось в восемь строк ;-). На Бейсике -- десять. Длиннее всего на Фортране -- около 25 строк. А вот и описание:
Чтобы по данной перестановке P=(p1, p2, ..., pm) чисел 1, 2, ..., m построить не- посредственно следующую мы будем просмат- ривать числа p1, p2, ..., pm с конца. И остановимся, когда впервые попадется член pi, меньший стоящего правее него (pi<pi+1). Если такого члена нет, то пе- рестановка P имеет вид (m,m-1,...,1), то есть является последней. Ясно, что члены pi+1>pi+2>...>pm образуют убывающую пос- ледовательность. Найдем среди них первый (если их рассматривать с конца) член pj, уже больший чем pi, и поменяем их местами. Остается переставить члены pi+1, pi+2, ..., pm в порядке возрастания, и искомая перестановка (назовем ее Q=(q1,...,qm)) будет получена.
> Кстати, если Вам еще не надоело, то раз уж зашла речь о рекурсиях, то вот еще один вопрос: какую глубину выдерживает вычисление функции Аккермана, ну, например, в Common-Лиспе? В принципе, интерпретатор у меня есть. Можете написать здесь корректное решение?
Вы имели в виду cLisp? Это "СИ-лисп", поскольку большая часть его внутренностей написана на си. Много не выдержит - несколько сотен или тысяч. Аккерман "плох" тем, что не сворачивается в хвостовую рекурсию. Но если "развернуть" его, то у вас памяти не хватит для вычисления хотя-бы от (4, 2) :)
> Сейчас уже и не вспомню суть, но, кажется
Ну вот тема императивщины и раскрыта наконец. Вместо того, чтобы
записать нормальную человечью фразу используя синтаксис машинного
языка, оказывается можно проявлять чюдеса изобретательности и остроумия
:D
> какую глубину выдерживает вычисление функции Аккермана,
ну, например, в Common-Лиспе?
Как и в любом другом наречии, зависит от метода вычисления
и от доступной оперативы.
> Можете написать здесь корректное решение?
Не спец по функциям Аккермана. Вот что произвелось,
но не утверждаю то моё оптимально
(declaim (optimize (speed 3) (safety 0)))
(defun ack (m n &optional (hash (make-hash-table :test #'equal)))
(let* (
(arg (list m n))
(val (gethash arg hash)))
(if (null val)
(setf (gethash arg hash)
(cond
((= 0 m) (+ 1 n))
((= 0 n) (ack (- m 1) 1 hash))
(t (ack (- m 1) (ack m (- n 1) hash) hash))))
val)))
(compile 'ack)
> в подавляющем большинстве случаев рекурсия нормально
заменяется циклами.
Заменяется, да.
> Достаточно длинно, не спорю, целых
Какая фих разница сколько строк? Главное что это решение явно
гиморнее для человека. С ним и сложнее разобраться,
и сложнее выдумать. И противоестественнее. Решение же на лиспе -
попросту запись _человечьего_ определения
в терминах и синтаксисом лиспа.
> Попробуй перестановки наборов произвольной длины, без контейнеров и рекурсий, только циклами. Результат сюды пожалста.
А почему без контейнеров? Списки неотъемлимая часть Питона, они
находятся даже не в стандартной библиотеке, а в самом ядре языка.
К тому же, как без контейнеров передать аргумент (список значений
для перестановки) в функцию?
Я же не требую чтобы ты писал на лиспе без списков.
Есть задачи для которых рулит рекурсия. Перестановки очевидно одна
из таких задач. Никто против рекурсии и не возражает. А если решать
задачу с переставновками без рекурсии, понятно что фигня получится.
Недавно писал сочетания без рекурсии. Получилось страшно:
def generate_combination(m, n):
combination = range(n)
while True:
# print combination
yield combination
index = n - 1
while True:
combination[index] += 1
if combination[index] < m - (n - index - 1):
break
else:
if index > 0:
combination[index] = combination[index - 1] + 2
else:
return
index -= 1
val = combination[index] + 1
for i in xrange(index + 1, n):
combination[i] = val
val += 1
Но опять таки религия рекурсией пользоваться не запрещает, и
если надо в Питоне всегда её можно использовать.
Исключительно чтобы проверить тезис о том что низкоуровневое программирование с меньшей степенью абстракций более естественно.
> Списки неотъемлимая часть Питона, они находятся даже не в стандартной библиотеке, а в самом ядре языка.
А в сях нету
> как без контейнеров передать аргумент (список значений для перестановки) в функцию?
Как массив+длина
> Я же не требую чтобы ты писал на лиспе без списков.
И правильно. Хотя можно вполне без них обойтись, потому что в лиспе есть и массивы и хеши и ещё всякое. Только если не использовать более абстрактные конструкции, код на лиспе станет питоноподобным. А раз уж разговор тут перетёк в тему "высокоуровневое vs низкоуровневое программирование", дальнейшее обсуждение потеряет смысл.
> понятно что фигня получится.
Дык я и говорил что если конструировать код не в направлении из общих абстракций к частностям, а наоборот, фигня получится.
> Но опять таки религия рекурсией пользоваться не запрещает, и если надо в Питоне всегда её можно использовать.
Дело то не в рекурсии а в разных уровнях абстракции. Насколько питон отличается от асма или С благодаря заимствованиям из лиспа, таким как контейнеры, настолько и лисп отличяется от питона, так как включает больше высокоуровневых конструкций и применение их более просто, так как сама семантика языка на их основана.
Что-то я уже перестал понимать, о чём спор идёт. Мы про высокоуровневое vs низкоуровневое программирование или про функциональщину vs императивщину? Или просто LISP против всех? :)
> функциональном подходе это тоже можно сделать с помощью серии последовательных приближений, но каждый раз это будет "решение целиком", то есть, преодоление "смыслового разрыва" одним скачком. Это не до всех доходит. Лично я всегда вначале выписываю цикл, а потом сворачиваю его в функциональный вызов. То есть, преодолеваю ту же пропасть в два шага. Грубо говоря, есть также подозрение, что процедурная декомпозиция намного более естественна, чем функциональная. Правда, меня можно обвинить в том, что я не крутой перец. С другой стороны, а почему бы мне не предположить, что Вы делаете то же самое, только прячете от меня промежуточные результаты?
> Вот и получается, что все то время, пока Вы придумываете "оптимальную терминологию", вполне можно успеть изготовить приличную императивную штуку, решающую поставленную задачу.
Вот я и удивился. А так, пока вроде лисп против питон получается. На функциональщину против императивщину не тянет потому что под словом лисп я имею ввиду коммон лисп, а он не функциональный ниразу. Если есть ещё идеи, присоединяйся. Повестка дня ещё не утверждена и круг обсуждаемых вопросов можно расширить.
> Вместо того, чтобы записать нормальную человечью фразу используя синтаксис машинного языка, оказывается можно проявлять чюдеса изобретательности и остроумия.
Дыкть, пишется все это ровно один раз ;-).
> Главное что это решение явно гиморнее для человека. С ним и сложнее разобраться, и сложнее выдумать. И противоестественнее.
Неочевидно, что с решением на Лиспе проще разобраться. Лично для меня оно тоже противоестественно :-).
> Решение же на лиспе - попросту запись _человечьего_ определения в терминах и синтаксисом лиспа.
Я Вам тоже дал _человечье_ определение, которое оказалось достаточно записать в терминах и синтаксисом Паскаля. Кстати, можете повторить свое "человечье" определенье? Или хотя бы ссылку напомнить?
А мне еще особенно интересно послушать серию "Lisp против Forth". А че? Метапрограммирование в Форте есть? Есть. Простота структур данных есть? Есть? Языком системного программирования является? Является. Синтексис извращенный предлагает? Предлагает. Маргинален? Очень даже маргинален. Ну и, чем же Лисп лучше Форта?
;-)
> Ну как же! А на первое место мы попасть не собираемся?
А то! Мы еще тему логического программирования не затрагивали... ;-)
> Маргинален? Очень даже маргинален. Ну и, чем же Лисп лучше Форта?
Дык тем, что он _еще_ маргинальнее 8)
А вообще хотелось бы увидеть пример и/или ссылку на примеры метапрограммирования в Лисп (или Питон 8) ). А то я слышу "метапрограммирование", "синтаксис, идеальный для метапрограммированя", а что это - никто внятно не объясняет. И в Сети внятных примеров пока не нарыл.
дык если всё требуемое по разу но цельную неделю...
> Неочевидно, что с решением на Лиспе проще разобраться. Лично для меня оно тоже противоестественно :-).
достаточно очевидно ИМХО. Потому что намного меньше подробностей есть. Другое дело, что непривычно может быть. Но отрицать что запись с меньшим количеством незначащих подробностей читаецо луче ИМХО глупо.
> Я Вам тоже дал _человечье_ определение, которое оказалось достаточно записать в терминах и синтаксисом Паскаля.
Всё правильно. Только вот разница в длине и замысловатости определений преогромна. Моё можно сыскать в этом же треде пару страниц назад.
Кажется, начинает брезжить тусклый свет понимания... То есть: если макросы могут использовать всю мощь языка для генерации кода, то это уже метапрограммирование? (у нас в PL/I такое было :))
> А вообще хотелось бы увидеть пример и/или ссылку на примеры метапрограммирования в Лисп (или Питон 8) ). А то я слышу "метапрограммирование", "синтаксис, идеальный для метапрограммированя", а что это - никто внятно не объясняет. И в Сети внятных примеров пока не нарыл.
В comp.lang.python не раз обсуждалась необзодимость макросов в Питоне, как правило это получается диалог типа:
Lisp Lover (LL): В питоне нужны макросы для того чтобы сделать ...
Python Bydlockoder (PB): Это можно сделать при помощи стандартных возможностей языка (классы, замыкания, динамическое создание классов и т.д.).
Т.е. не было приведено вменямых use-case-ов где нужны макросы.
Гвидо придерживается позиции создания специального синтаксиса для закрытия таких use-case-ов, например List comprehensions, with (ну всё фанаты Руби больше не будут приставать со своим chdir-ом :-)
А по поводу того что Питон (да и все остальные языки) со временем всё больше и больше становится похож на Лисп (как говорит Грэм, да и в этой ветке эта мысль уже прозвучала) есть такая ссылка:
"Graham demonstrates the "power" of Lisp compared to Python by comparing tiny code snippets." - сразу видно, практик писал 8) Вот и мне обмен небольшими кусочками кода в этом треде кажется... несерьезным.
Лисп, конечно, был революционным языком, но сегодня его фишками никого не удивишь. Хотя я хочу многострочные ламбды в Питоне! 8)
> Как бы ты реализовал http://groups.google.com/group/comp.lang.lisp/msg/4fe888b58ffa83b8 ?
Вот так:
class Parser:
pattern_length = 4
def __init__(self, *readers):
self.readers = {}
for r in readers:
self.readers[r.pattern] = r
def parse(self, data):
for line in data:
reader = self.readers.get(line[:self.pattern_length], None)
if reader is not None:
yield reader.parseString(line)
class LineReader:
def __init__(self, pattern, class_, fields):
self.pattern = pattern
self.fields = fields
self.class_ = class_
def parseString(self, s):
obj = self.class_()
for field in self.fields:
setattr(obj, field[2], s[field[0]:field[1] + 1])
return obj
class SystemObject:
def __str__(self):
return self.__class__.__name__ + ' ' + str(self.__dict__)
class ServiceCall(SystemObject):
pass
class Usage(SystemObject):
pass
def main():
service_call_reader = LineReader('SVCL', ServiceCall, [
(4, 18, 'customer_name'),
(19, 23, 'customer_id'),
(24, 27, 'call_type_code'),
(28, 35, 'date_of_call_string')])
usage_reader = LineReader('USGE', Usage, [
(4, 8, 'customer_id'),
(9, 22, 'customer_name'),
(30, 33, 'cycle'),
(31, 36, 'read_date')])
data = """
SVCLFOWLER 10101MS0120050313.........................
SVCLHOHPE 10201DX0320050315........................
SVCLTWO x10301MRP220050329..............................
USGE10301TWO x50214..7050329..........................""".splitlines()
parser = Parser(service_call_reader, usage_reader)
for obj in parser.parse(data):
print obj
if __name__ == '__main__':
main()
Суть таже самая. Формат строки объявляем декларативно.
Вот тебе и DSL в Питоне :-)
Т.е. получилось длинее чем у них, но у меня код много чище (ИМХО):
1. Отдельный класс на парсер. У них просто разбирают строки в main-e
У меня есть возсожность использовать Parser повторно
2. Отдельный классы на SystemObject, ServiceCall, Usage. Т.е. возможность объявить разные методы у разных классов.
3. Переопределённый __str__. У них насколько я понял, используется
стандартное строковое представление объектов.
4. Четвёрка у меня именнованная константа, у них magic number
5. И какой код будет легче поддерживать? :-)
> Лисп, конечно, был революционным языком, но сегодня его фишками никого не удивишь.
Да, не удивишь. Но догнать его так никто и не смог...
Или уже есть язык, в котором всю его мощь можно использовать для кодогенерации, причём в теле основной программы, а не внешним/сторонними трансляторами?
Кто-то недавно ссылался на парсер перла на перле... Ну напишите макрос, который будет использоваться _при_ (а не _в_) определении другого макроса, который будет... И так столько, сколько надо. Причём в одном файле, а не клепая левую либу. И чтобы это не было костылём... Потом покажите, как это можно отлаживать. И как можно посмотреть, во что итоговый макрос раскручивается при тех или иных данных.
Хотя, зачем вам такие сложности? Подом сиди и ломай голову - что ты вызываешь, ибо если функцию, то сначала, как и положено, вычисляться параметры, а потом сама функция, а если макро - фиг его знает будут ли параметры вычисляться вообще. А ещё есть макро для компиляции, и результат их "раскрутки" может быть несколько иной, чем в интерпретаторе (где это вообще может быть функцией). Спотыкайся о то, что типы не есть классы, а классы не есть типы. Да, один loop чего стоит, ибо похож больше на питон, чем на лисп (хотя питону такое и не снилось). Опять же, разобрать чужой код, написанный правильно, иногда сродни ребусу: одни макросы вызываются при построении других, а последние просто вызываются один раз при инициализации каких-то данных, причём повторить этот трюк в интерпретаторе просто так нельзя, ибо на эти данные завязана работа самой среды... Охренеть можно. А выкрунтасы с readtable - это даже не макросы (это может быть как макро в си, а может быть интерпретатор другого языка - SQL например, или XML/HTML/всего чего угодно...) Что ещё? Internal type/class могут не наследоваться. А разные области имён для функций и переменных - вообще сказка - как вам такое:
(setf (slot-value foo 'foo) (foo 'foo :foo foo))
И чем дальше в лес, тем толще партизаны... Нафиг, бросайте вы эту дурную затею ;)
Ага, страница кода конечно лучше, чем два десятка строк - вопросов нет!.. :)
> 1. Отдельный класс на парсер. У них просто разбирают строки в main-e У меня есть возсожность использовать Parser повторно
А на лиспе кто-то запрещает код использовать повтороно? Там только пример. Переделать на функции - больше кода не станет :)
> 2. Отдельный классы на SystemObject, ServiceCall, Usage. Т.е. возможность объявить разные методы у разных классов.
Ну а там лепи себе defmapping под свои нужды - и всех делов. Хоть ещё для десятка типов. В чём твоё преимущество?
> 3. Переопределённый __str__. У них насколько я понял, используется стандартное строковое представление объектов.
Вот тут я тебя не понял.
> 4. Четвёрка у меня именнованная константа, у них magic number
Это даже не смешно. Это же был пример на скорую руку. Ещё одна строка кода - всего-то. Или более того - вынести не 4-ку, а (subseq line 0 4) (а то и вместе с internal) в функциональную переменную, и определяй себе тип как твоей душе угодно.
> 5. И какой код будет легче поддерживать? :-)
Не твой - 100% :) Если конечно ты не знаешь лисп, ну тогда ССЗБ ;)
> Гвидо придерживается позиции создания специального синтаксиса для закрытия таких use-case-ов, например List comprehensions, with (ну всё фанаты Руби больше не будут приставать со своим chdir-ом :-)
Вот-вот, какой Гвидо решил создать синтаксис, таким вы пользоваться и будете. А тут пиши себе свой хоть по одному на каждый день недели... ;)
> Ну, это слишком круто пока, и по советам людей двигаться как-то проще. Кроме того, мой основной интерес - Python.
Очень хорошо. Попрактикуйся основательно в питоне (при этом лисп не забывай). И весьма вероятно, что в один прекрасный день (или чёрный - кому как) ты пошлёшь этот питон со всеми его ограничениями к едреней фене... Не факт, что после этого посмотришь на лисп... Дык, я и говорил, каждый на поле образования, устланного граблями, ходит по собственной траектории...
> если макросы могут использовать всю мощь языка для генерации кода, то это уже метапрограммирование?
Не. Всю свою мощ макросы и в сях могут юзать, вот только мощи-то там... Метапрограммирование - это когда создаёш наречие специально для решения данной задачи и затем прогу, написанную на этом наречии обращаеш в код на извесном языке, например лиспе.