LINUX.ORG.RU

[lisp] несколько гадостей

 


1

0

Пора всё же написать про лисп несколько гадостей (уже наболело).

1. По де-факто стандарту определение пространства имён и реализация этого пр-ва имён - это два разных файла. Т.е., как в С, а не как в Паскале. Это неудобно и вообще прошлый век.

Нет операции (with-namespace &body body) - может быть, её и можно сделать, но по-нормальному её можно сделать только через модификацию readtable. Но если две подсистемы меняют readtable и (не дай Бог) поменяют один и тот же символ, то между ними будет проблема и конфликт. Поэтому, для низкоуровневых вещей, которые потом предполагается включить в свой постоянный инструментарий, readtable менять нежелательно. А если импортировать множество разных мелких пр-в имён, то неизбежны конфликты при импорте. То есть, среда не поощряет создания множества мелких пространств имён, а поощряет создание небольшого числа крупных. А это плохо (жду конструктивных возражений).

2. Вообще, убогие пространства имён. Они не могут быть вложенными, как a::b::c. Только "плоские" пространства имён a::b В обычных языках, как правило, класс/структура задают пр-во имён. Собственно, если и есть в ООП какая-то сила, так это в том, что не нужно писать instance.field, а можно просто написать field, если находишься внутри метода. А вовсе не в том, что думают об этом апологеты ООП. В лиспе так написать нельзя (хотя есть конструкция with-slots, но в маленьких функциях она не помогает сократить код).

3. многословность. Сложение двух строк по стандарту (concatenate 'string "as" "df") а также в стандарте некоторым примитивным операциям присвоены имена, подобные destructuring-bind или multiple-value-bind

4. Вместо мойЛюбимыйИдентификатор нужно писать мой-любимый-идентификатор. Вроде мелочь, а места на экране жрётся море. Конечно, никто не заставляет, но есть проблемы с введением идентификаторов, чувствительных к регистру, поскольку в стандарте по умолчанию всё приводится к верхнему регистру и все стандартные символы - в верхнем регистре. То, есть, (print 'мойЛюбимыйИдентификатор) = МОЙЛЮБИМЫЙИДЕНТИФИКАТОР

5. Отсюда - следствие: В обычных языках пишем instance1.field1.field2 В лиспе (в лучшем случае) - (field2-of (field1-of instance1)) 4 лишних символа на каждую ссылку, не считая пробела, который тоже жрёт место на экране. Если брать голый, ничем не подслащённый стандарт, то может оказаться и (slot-value (slot-value instance1 'field1) 'field2)

6. Дебаггер. Вряд ли получится посмотреть переменные в том виде, как они определены в исходнике. Компилятор слишком умный и их соптимизирует. Вряд ли получится поставить брекпойнт на точке в исходнике, по той же причине. Отлаживаться нужно через логи и трейсы. Впрочем, динамичный характер языка делает такую отладку лёгкой.

7. Не хватает множества идиом. Например, есть push (деструктивно добавить элемент в начало списка). Но нет nconcf (добавить к переменной, содержащей список, другой список). Поскольку эти идиомы реально нужны, каждый вводит их по-своему и единый язык распадается на множество диалектов. То же сложение строк никто не делает как (concatenate 'string ...) Я ещё не вполне в культуре, но я не думаю, что есть де-факто стандарт на сокращённую запись этого выражения.

8. CLOS. Да, CLOS велик и могуч, в нём есть мультиметоды. Но в нём есть и такая фишка, как "изменить класс в рантайме". Это круто, но это - накладные расходы.

9. Отсутствует декларативная статическая типизация. Да-да, она самая. На самом деле, информация, содержащаяся в определении типов, очень помогает писать более лаконичный код. На самом деле, возможность (необязательной) статической типизации в лиспе есть, но нет возможности использовать её для сокращения кода.

Конечно, да. Лисп велик и могуч и на нём можно делать то, что нельзя больше делать ни на чём другом. У него есть такие степени свободы, которые продвинутый си-плюс-плюсник просто никогда в жизни не сможет осознать. Но... Обычный язык общего назначения в лиспе нужно тоже делать DSL-ем. В том числе, нужен и DSL для полноценной работы со списками (а уж это - основа лиспа). DSL для удобного определения CLOS-классов. Каждый пишет такой DSL, но нет стандарта де-факто. Я об этом уже писал.

Последнее время я работаю с лиспом более плотно, чем раньше. Я уже начинаю сомневаться в целесообразности темы "лисп как препроцессор для С". Есть и практические к тому иллюстрации. Лисп сообщество не смогло по сей день решить некоторые тривиальные задачи:

1. asdf. Не умеет делать clean (т.е., нет стандарта на эту операцию). Не умеет пересобирать часть систем. Например, если я говорю recompile :force t своей системе, у меня пересобирается вся лисповая часть sbcl. И это - только одна из недоделок asdf. Т.е., при всей крутости лиспа, де-факто стандартное средство сборки гораздо слабее, чем make.

2. средства автодокументирования. Несмотря на то, что в лиспе делать автодокументацию на порядок удобнее, чем в каком-нибудь там С++, я не нашёл средства документированиия, подобного doxygen по мощности. Только не надо меня лечить, что есть describe и т.п. Документация удобна, когда она существует в виде книжечки. Один раз прочитал - и уже знаешь, куда тыркаться. Интерактивная помощь нужна, если что-то забыл, разбираться по ней не всегда удобно (хотя apropos рулит, конечно).

Лисперы, ваши комменты приветствуются. Особенно, в части решения означенных проблем.

Я не ставлю себе цель обосрать лисп. На самом деле, я всё равно хочу писать на лиспе. Просто я давно пытаюсь понять - если он так крут, то почему же он уступил своё первое место мейнстрим-языка высокого уровня какой-то там Яве? Мне кажется, что я привёл здесь причины, основная из которых, если обобщать - лисп неудобен для простых вещей, в которых не нужны макросы. А этих простых вещей всё же больше. Видимо, при разработке следовало сделать более лёгким основной синтаксис. Создание макросов затруднилось бы, но макросов в коде обычно не больше 10-20%, так что общая трудоёмкость могла бы снизиться, а удобочитаемость заведомо повысилась бы.

И, конечно, интересно найти выход из этого положения.

★★★★★

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

den73 ★★★★★
() автор топика

Да, по поводу документирования - существует где-то так около десятка (если не больше) literate programming tools для Лиспа.

anonymous
()

по поводу длинных идентификаторов - надо использовать соответствующие инструменты. Тот же slime позволяет написать (m-v-b и получить раскрытие этого в multiple-value-bind, и т.п.

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

анонимус, я видел их в каталоге cl-user.net, читал некоторые доки и остановился на tinaa. Конкретно, doxygen позволяет делать ссылки внутри докстрингов на другие разделы справки, а также создавать разделы, не привязанные ни к чему, например, "введение" или "туториал" (блин, как это будет по-русски?) Также он создаёт в документации несколько точек входа, по иерархии классов и по файлам. Также он позволяет открыть любой исходник (создаёт все исходники аннотированные в html и расставляет на них ссылки). Tinaa так не умеет.

Ткните меня носом в аналогичные возможности в лисповых аналогах. Если Вас не затруднит. При этом, естественно, он должен читать штатные докстринги, а не только комменты. У меня не было полдня перепробовать все эти средства. Если Вы говорите, то, наверное, знаете больше меня?

den73 ★★★★★
() автор топика

1. На вкус и цвет товарищей нет.

2. см п.1 Вот лично мне всякие with'ы - поперек горла. И, например, на яве я всегда пишу this.field, эта привычка осталась от питона, и как показывает практика, очень полезна.

3. Решается средствами IDE.

4. Традиции. Лично мне тоже совершенно не понятно как язык может быть нечувствителен к регистру символов.

5. Тоже традиции. Кроме того, прямой доступ к свойствам объекта, в ООП-мире - моветон.

6. Зачем? Грамотно организованный лог скажет об ошибке больше, чем любой дебаггер, а юнит-тесты помогут избежать трудноуловимых ошибок. А как ты собрался дебажить многопоточную программу, например?

7. Тут я тебе ничего не скажу, ибо не лиспер :P

8. Ха-ха-ха. Почитай например про javassist:

>Javassist (Java Programming Assistant) makes Java bytecode manipulation simple. It is a class library for editing bytecodes in Java; it enables Java programs to define a new class at runtime and to modify a class file when the JVM loads it.

Как видишь, делают то же, только с помощью грязного кривого костыля.

Давно уже пора покончить с расовой дискриминацией некоторых сущностей: например переменная - это объект первого класса, а функция почему-то нет. Тем более, совершенно не понятно, какого хрена класс не является объектом первого класса. Даже в яве 1.5 это сделали только наполовину.

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

9. Ну, про статическую типизацию - вопрос сложный. Тем более про Хиндли-Милнера (ты ведь ее имеешь ввиду?). Все-таки язык для ее полноценной поддержки должен реализовывать вещи типа паттерн-матчинга. Конечно, если в коммон лисп ее введут, то это будет СОБЫТИЕ, хотя CL перестанет быть CL.

Самая главная проблема лиспа в том, что нет ни одной нормальной реализации. Про реализации, ценой в несколько килобаксов, я молчу.

Вторая проблема в том, что под лисп нет устойчивых API, реализации которых поставляют _независимые_ производители.

И ситуация кардинально не изменится, до тех пор, пока кто-то из игроков на рынке лисп-решений не решит сделать "ход доской по голове" и не откроет свое многокилобаксовое решение под более-менее открытой лицензией.

Macil ★★★★★
()

1, 2 (пространства имён): да, слабовато смотрится.

3 (многословность): да, возможно. С другой стороны, однообразность синтаксиса и "человеческие" названия лично мне кажутся понятней, чем "плящущие человечки" в ML. К тому же, мозг работает с целым тегом, а не символами в нём, т.е. multiple-value-bind мной воспринимается, как одна короткая сущность. Впрочем, это индивидуально.

Да, кое-что в стандарте можно было бы переделать по части лаконичности и однообразности.

4: вообще не проблема.

5: имхо, обязательная предикатность - один из основных элементов, дающий языку униформность. Куда больше раздражает, что в OCaml можно записывать некоторые операции в предикатной форме, но только некоторые.

6 (дебаггер): в других языках всё то же самое: если задрать машинную отпимизацию, то куска кода, на который хочется поставить bp, может и не существовать, либо размазаться по километрам маш.кода. В лиспе с выключенной отпимизацией код (не макросы) прямо транслируется в байткод (или vop, virtual operation, который имеет паттерны в маш.кодах для каждой поддерживаемой компилятором платформы), т.е. каких-то особых, отличных сложностей в отладке не должно быть.

7: Да, хотелось бы, чтобы стандарт языка раз в несколько лет пересматривали.

8 (ООП): CLOS - это одна из реализаций ООП. Никто не мешает использовать другую реализацию попроще (или написать свою с минимумом требуемых возможностей).

9 (типизация): существуют работы по статической типизации во время компиляции в Лиспе, например, "Strong Static Type Checking for Functional Common Lisp" Роберта Акерса. Существует также язык Qi, который написан на Лиспе, но имеет систему типов ещё жёстче, чем, допустим, в OCaml. Причемательно, что типизация в Qi опциональная, поэтому на ранних стадиях разработки можно не тратить время на замену операции на такую же, но для другого типа.

10 (asdf): напишите своё :) Лисп, по сути, очень маленький язык. Всё остальное сделано в виде библиотек.

> И, конечно, интересно найти выход из этого положения.

Люди пишут свои лиспоподобные языки :) Как правило, на основе всё тех же scheme или cl.

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

> Все-таки язык для ее полноценной поддержки должен реализовывать вещи типа паттерн-матчинга. Конечно, если в коммон лисп ее введут, то это будет СОБЫТИЕ, хотя CL перестанет быть CL.

Хм, а destructuring-bind зачем? И вообще, в CL всё принято делать в виде библиотеки :) Вот Петя Норвиг в Paradigms of artificial programming ажно две версии п-матчинга написал.

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

> Самая главная проблема лиспа в том, что нет ни одной нормальной реализации. Про реализации, ценой в несколько килобаксов, я молчу.

SBCL. Вот в этом тесте http://www.ffconsultancy.com/ocaml/ray_tracer/languages.html SBCL у меня в оптимизированном варианте отрендерил картинку за 6 секунд (оптимизированный OCaml за 3), а AllegroCL 8.1 - за ~370.

> Вторая проблема в том, что под лисп нет устойчивых API, реализации которых поставляют _независимые_ производители.

Есть. Зовётся ANSI Common Lisp. Все реализации, которые это поддерживают, совместимы между собой. Естественно, в рамках той совместимости, которая обычно в реальной жизни бывает ;)

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

>Есть. Зовётся ANSI Common Lisp.

Поддержка unicode? Парсинг XML (SAX/DOM/Xpath/XSL)? GUI? Сеть/веб-приложения? Доступ к СУБД? Безопасность (kerberos/LDAP/PKI/PKCS#11/SASL/SSL)?

Я уж не говорю про разные "ентерпрайзные" фишки.

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

> Поддержка unicode? Парсинг XML (SAX/DOM/Xpath/XSL)? GUI? Сеть/веб-приложения? Доступ к СУБД? Безопасность (kerberos/LDAP/PKI/PKCS#11/SASL/SSL)? Я уж не говорю про разные "ентерпрайзные" фишки.

Это называется platform. И какое отношение имеет LDAP к безопасности?

mv ★★★★★
()

Открой для себя метопрограммирование.

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

В Java SE есть Swing. Про Qt или Gtk там ничего нет, про него вроде речь не шла.

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

>И какое отношение имеет LDAP к безопасности?

LDAP - одна из практических реализаций x.500, в LDAP могут храниться сертификаты, в LDAP можно хранить пароли или ключи, LDAP исползуется вместе с kerberos'ом в AD, eDirectory, ApacheDS, Redhat(Fedora)DS.

>Это называется platform.

Ну да, называется. В принципе, мой предыдущий пост некорректен: язык это одно, а платформа это другое.

Но, приложения мы разрабатываем на платформе. Да и ведущие игроки выпускают не только голую реализацию (коммон)Лиспа.

Все мои попытки разработки реальных приложений на Lisp, Ocaml, Erlang, Haskell, упирались в отсутствие или феерическую кривость казалось бы простейших вещей и очень нужных вещей.

И если честно, меня это крепко достало. И хоть я плююсь от "ентерпрайзного" ООП вообще, и от явы в частности, приходится признавать некоторые ее преимущества... Правда подчас чувствую себя одной из миллиона обезьян, которая пишет Войну и Мир :).

Macil ★★★★★
()

>2. Вообще, убогие пространства имён. Они не могут быть вложенными, как a::b::c. Только "плоские" пространства имён a::b В обычных языках, как правило, класс/структура задают пр-во имён.

>И, конечно, интересно найти выход из этого положения.

Ну хорошо. А мы-то чем поможем? :) Я, например, спокойно обхожусь одним уровнем, поэтому особо и не вдавался в вопрос. Однако задачу вложенных package как-то решают. Есть реализация вложенных пакетов для Allegro и CMUCL. Говорят, что по одной спецификации делали:

http://common-lisp.net/project/cmucl/doc/cmu-user/extensions.html#toc20

Реализация какая-то есть у Tim Bradshaw. Называется Conduits:

http://www.tfeb.org/lisp/hax.html

Ну и т. д. И разговоров об этом много было на c.l.l. Наверняка и ссылочки, и решения какие-нибудь найдутся.

Zubok ★★★★★
()

>8. CLOS. Да, CLOS велик и могуч, в нём есть мультиметоды. Но в нём есть и такая фишка, как "изменить класс в рантайме". Это круто, но это - накладные расходы.

Были и другие реализации объектных систем (например, KR, http://www.cliki.net/KR). Только нафига это нужно? CLOS стандартизирован и *уже* в ядре. Так что решение простое: не надо использовать лишнюю (для тебя) функциональность -- не используй.

Zubok ★★★★★
()

Вообще очень одобряю твой порыв написать

1. что от языка требуется

2. что от языка не требуется (тот же "изменить класс в рантайме")

> "лисп как препроцессор для С"

Лексический препроцессор для С нужен, то что это лисп -- сомневаюсь.

> Видимо, при разработке следовало сделать более лёгким основной синтаксис. Создание макросов затруднилось бы, но макросов в коде обычно не больше 10-20%, так что общая трудоёмкость могла бы снизиться, а удобочитаемость заведомо повысилась бы.

Вот это по-моему самая перспективная идея. Стучись в джаббер list.ru.list.ru собака gmail.com или оставь свой для общения на эту тему.

Ее реализуют, но пока что с косяками.

В D уже есть ленивые аргументы функций. Макросы есть в питон-подобном Немерле.

Кстати: как в лиспе будет записываться что-то вроде (предскажу: ужасно):

<table><tr><td width=100>abcd<td width=200>efgh</table>

По остальным пунктам: боюсь что Лисп порядком тяготит совместимость.

> Каждый пишет такой DSL, но нет стандарта де-факто. Я об этом уже писал.

"и чтобы DSL, и выглядел стандартно"? Это скорее опять Немерле, но там свои косяки.

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

> CLOS стандартизирован и *уже* в ядре. Так что решение простое: не надо использовать лишнюю (для тебя) функциональность -- не используй.

Допустим, у меня нет ни одного класса, который я меняю на лету. Будет ли мой код таким же быстрым, как в С++ ?

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

Кстати: я тут не разжигаю флейм С++ vs. Lisp.

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

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

> Кстати: как в лиспе будет записываться что-то вроде (предскажу: ужасно): <table><tr><td width=100>abcd<td width=200>efgh</table>

(:table (:tr (:td :width 100 "abcd") (:td :width 200 "efgh")))

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

>Прикол в том, что в случае с CLOS платить нужно сразу за всё.

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

Я копипастил кусок кода по замеру вызова метода по одному объекту и вызова defun.

http://www.linux.org.ru/jump-message.jsp?msgid=2848829&cid=2858423

На SBCL такой метод вызывается медленнее defun в 1.6 раза, а на CLISP -- в 2 раза. Учитывая, что в теле функции в общем случае времени проводится больше, чем вызывается этот метод, то в таком конкретном случае получаем небольшое падение производительности. Можете проверить у себя. Можно тест развить на более изощренные тесты мультиметодов, где выбор по двум, трем объектам и т. д.

Не знаю, правильно ли я понял твою фразу "про платить сразу за все". Это, наверное, и к вопросу CL vs C++. Проще сразу сказать, что с CLOS быстрее, чем C++ не будет.

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

>>Прикол в том, что в случае с CLOS платить нужно сразу за всё.

В том числе за то, что не нужно -- например, изменение классов на лету?

> Проще сразу сказать, что с CLOS быстрее, чем C++ не будет.

Быстрее не обязательно. А вот будет ли так же быстро, если изменение классов на лету мне не нужно?

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

> (:table (:tr (:td :width 100 "abcd") (:td :width 200 "efgh")))

Насколько длинным (в наиболее удобном фреймворке, либке, ...) будет выглядеть для этого аналог DTD -- т.е. внутри таблицы несколько tr, внутри них несколько td, и при несоблюдении этого или опечатке, например :witdh, ошибка времени компиляции?

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

>Быстрее не обязательно. А вот будет ли так же быстро, если изменение классов на лету мне не нужно?

Замерь -- обсудим. У меня (так как вопрос мне) ни замеров, ни ссылок нет. Да и не парит меня скорость по отношению к Си++. В подавляющием большинстве приложений эта скорость никого не волнует. А где нужна оптимизация -- будет оптимизация. Куда важнее завязнуть с крупным проектом не на десять лет, а, скажем, на пять. Поэтому важнее эффективность работы. Оптимизация вторична. Жизнь коротка. :)

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

>Я копипастил кусок кода по замеру вызова метода по одному объекту и вызова defun.

>http://www.linux.org.ru/jump-message.jsp?msgid=2848829&cid=2858423


>На SBCL такой метод вызывается медленнее defun в 1.6 раза, а на CLISP -- в 2 раза.


CL-USER> (lisp-implementation-type)
"SBCL"
CL-USER> (lisp-implementation-version)
"1.0.20.5"

Evaluation took:
0.050 seconds of real time
0.049992 seconds of total run time (0.049992 user, 0.000000 system)
100.00% CPU
108,947,762 processor cycles
0 bytes consed
Evaluation took:
0.172 seconds of real time
0.171974 seconds of total run time (0.170974 user, 0.001000 system)
100.00% CPU
377,034,570 processor cycles
16,096 bytes consed
Evaluation took:
0.354 seconds of real time
0.350947 seconds of total run time (0.350947 user, 0.000000 system)
99.15% CPU
776,663,448 processor cycles
16,320 bytes consed

Для defun, generic и typecase соответственно.

> Не знаю, правильно ли я понял твою фразу "про платить сразу за все". Это, наверное, и к вопросу CL vs C++.


Нет, в не-CLOS части тот же SBCL довольно неплохой код генерирует. Конечно, всё равно более медленный, чем у более слабых языков со статической типизацией, но для своих возможностей код всё равно неплохой.

> Проще сразу сказать, что с CLOS быстрее, чем C++ не будет.


Именно.

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

C++/10 лет vs CL/5 лет выглядит неправдоподобным. Разве что, если в случае с CL первые года 3.5-4 пробовать писать на C++...

mv ★★★★★
()

1 это хорошо и правильно, потому что позволяет не волочь весь код в те места, в которых весь код и не нужен.

> Нет операции

Нету. Однако use-package/unuse-package и export/unexport должны удовлетворить самых взыскательных пользователей. Трогать readtable - действительно совсем плохая идея.

> То есть, среда не поощряет создания множества мелких пространств имён, а поощряет создание небольшого числа крупных.

Это отчасти верно. Это отчасти хорошо, не надо путаться в ста мелких пакажах. От другой части - use make-package, Luke, чтобы создать наиболее подходящий набор символов для текущего участка кода.

> Вообще, убогие пространства имён.

Зато ты можешь оперировать ими как угодно, для этого есть инструменты. Lisp way: как можно большая гибкость с как можно меньшими фиксированными рулесами.

> Они не могут быть вложенными, как a::b::c.

Могут, так как при помощи макросов можно черезвычайно легко сделать прозрачное преобразование например из a::b::c в temp-package::a-b-c. ИМХО, если это кому-то позадобилось, значит кто-то что-то делает не правильно.

> Cобственно, если и есть в ООП какая-то сила, так это в том, что не нужно писать instance.field, а можно просто написать field, если находишься внутри метода.

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

> многословность

Дань большей простоте и понятности. ИМХО проще работать с подобными (concatenate 'string) и (concatenate 'list), нежели иметь загадочный ероглиф на каждый случай. Впрочем, опять-таки, совсем несложно замапить все эти операции например на (+ "abc" "def"). Если сделаешь - ССЗБ, но всё возможно...

> Вместо мойЛюбимыйИдентификатор нужно писать мой-любимый-идентификатор

дело вкуса. Вариант - |мойЛюбимыйWtfElse|. Простенько, читаемо, и регистрозависимо, всё как тебе нравится.

> 5. Отсюда - следствие: В обычных языках пишем

Ога. А ещё там (setq ) вместо = "обычного" языка. Разница в том, что в "обычном" языке тебе надо набирать = вручную, а в лиспе тонны slot-value генерятся макросами, что в итоге оказывается проще.

> Каждый пишет такой DSL, но нет стандарта де-факто.

Верно, это как раз к вопросу о том, откуда взялась буква "D" в аббревиатуре "DSL".

Вобщем, и дальше в том же духе. Замечания по сути правильные, но произошли они из-за попыток неправильно использовать лисп, наподобие того как забивать гвоздь шляпкой вперёд. Осваивай DSL и метапрограммирование, и эти проблемы совершенно перестанут тебя беспокоить.

anonymous
()

1 это хорошо и правильно, потому что позволяет не волочь весь код в те места, в которых весь код и не нужен.

> Нет операции

Нету. Однако use-package/unuse-package и export/unexport должны удовлетворить самых взыскательных пользователей. Трогать readtable - действительно совсем плохая идея.

> То есть, среда не поощряет создания множества мелких пространств имён, а поощряет создание небольшого числа крупных.

Это отчасти верно. Это отчасти хорошо, не надо путаться в ста мелких пакажах. От другой части - use make-package, Luke, чтобы создать наиболее подходящий набор символов для текущего участка кода.

> Вообще, убогие пространства имён.

Зато ты можешь оперировать ими как угодно, для этого есть инструменты. Lisp way: как можно большая гибкость с как можно меньшими фиксированными рулесами.

> Они не могут быть вложенными, как a::b::c.

Могут, так как при помощи макросов можно черезвычайно легко сделать прозрачное преобразование например из a::b::c в temp-package::a-b-c. ИМХО, если это кому-то позадобилось, значит кто-то что-то делает не правильно.

> Cобственно, если и есть в ООП какая-то сила, так это в том, что не нужно писать instance.field, а можно просто написать field, если находишься внутри метода.

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

> многословность

Дань большей простоте и понятности. ИМХО проще работать с подобными (concatenate 'string) и (concatenate 'list), нежели иметь загадочный ероглиф на каждый случай. Впрочем, опять-таки, совсем несложно замапить все эти операции например на (+ "abc" "def"). Если сделаешь - ССЗБ, но всё возможно...

> Вместо мойЛюбимыйИдентификатор нужно писать мой-любимый-идентификатор

дело вкуса. Вариант - |мойЛюбимыйWtfElse|. Простенько, читаемо, и регистрозависимо, всё как тебе нравится.

> 5. Отсюда - следствие: В обычных языках пишем

Ога. А ещё там (setq ) вместо = "обычного" языка. Разница в том, что в "обычном" языке тебе надо набирать = вручную, а в лиспе тонны slot-value генерятся макросами, что в итоге оказывается проще.

> Каждый пишет такой DSL, но нет стандарта де-факто.

Верно, это как раз к вопросу о том, откуда взялась буква "D" в аббревиатуре "DSL".

Вобщем, и дальше в том же духе. Замечания по сути правильные, но произошли они из-за попыток неправильно использовать лисп, наподобие того как забивать гвоздь шляпкой вперёд. Осваивай DSL и метапрограммирование, и эти проблемы совершенно перестанут тебя беспокоить.

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

Так. Начнём с конца.
> Замечания по сути правильные, но произошли они из-за попыток неправильно использовать лисп

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

Zubok, огромное спасибо за ссылку на hierarchical packages. Разгребусь - обязательно опробую в деле. И макрос там есть. Жаль только, что это #@. Я бы сделал #with-что-то () или же #w-что-то. Это было бы лиспово на вид и позволило бы присвоить одному и тому же сочетанию #w множество разных смыслов одновременно (заведя соответствующую таблицу диспетчеризации, классифицирующую "что-то"). Потому что (не помню, писал ли уже об этом) при попытке подсоединить две либы, использующих одни и те же macro characters, происходит катастрофа. А macro-character-ов не так уж много. Вопрос только один - к sbcl эти иерарх. пакеты применимы?

linux_org_ru, помоему, у меня в профайле есть мыло. Нет? Джаббером я не пользуюсь, поэтому и постучать в него не могу :)
> "и чтобы DSL, и выглядел стандартно"?

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

Кто-то писал о сокращениях m-v-b, но ведь это сокращения только для письма, а код нужно ещё и читать! Это на высоком уровне мозг уже фильтрует multiple-value-bind и сокращает его (intern ему делает), графический-то процессор при чтении такого текста занят на полную. Да и объём кода, который помещается на экране, при этом становится меньше.

Короче, я сейчас думаю о такой вещи: сделать моду для emacs, в которой обратимым образом во время отображения-записи в буфер производятся сокращения. Например, делаем функцию "преобразовать идентификатор", которая меняет for-each на forEach, multiple-value-bind на mVB и т.п.
Но всё это не существует на диске, существует только на экране.
Также неплохо бы произвести совмещение вложенных конструкций, что-нибудь типа:

(macrolet ((m () z)) (let ((a b)) (flet ((e () x)) body!)))
менять на
{(macrolet (m () z)) (let (a b)) (flet (e () x)) body!}

далее, заменять цепочки разыменований

(setf (color-of (body-of widget)))
на
widget.body.color

символы, содержащие точку, брать в ||
lambda заменять на греческую лямбду. Хех, а если пойти дальше, можно заменять def в начале слова на дельту, а with - на омегу.

Самое главное, что такое преобразование обратимо и не напрягает НИКОГО из читателей твоего кода - они получают лисп во всей его чистоте.

Кстати, этот подход применим и к другим языкам.

> Все мои попытки разработки реальных приложений на Lisp, Ocaml, Erlang, Haskell, упирались в отсутствие или феерическую кривость казалось бы простейших вещей и очень нужных вещей.

Нда, и я примерно о том же. Хотя пока что я ещё склонен барахтаться. И есть ведь ещё тема "лисп как препроцессор для Java" и эта тема даже куда как более плодотворна, ведь можно и байт-код генерить.

mv, destructuring-bind - это не совсем pattern-matching, т.к. исключение порождает. Но если его перехватить, то получается в чём-то лучше pattern-mathing-а. Меня, например, интересует задача эффективно извлекать/записывать keyword аргументы из &rest при вложенных вызовах и destructuring-bind как раз для этого подходит.

> (asdf): напишите своё :) Лисп, по сути, очень маленький язык. Всё остальное сделано в виде библиотек.


Нда, а как мне пользоваться тем, что уже поставляется в виде asdf-систем? Ну и вообще, если вы любому программеру на С предложите написать свой make, я даже не могу представить, куда он Вас пошлёт.

Понимаете ли, я лиспом не просто развлекаюсь. Я пытаюсь им зарабатывать деньги на жизнь. Мне некогда писать свой asdf, автодокументатор, pattern matching и всё такое прочее. У меня, в крайнем случае, есть время почитать вылизанную доку по ним. Кстати, если уж говорить о pattern-mathing-е, я видел 2-3-4 либы по нему. И все они - полный отстой. В итоге, я пользуюсь какой-то самой маленькой, выдранной из abcl(r), которую уже сам докручиваю. Если кто-нибудь знает полноценную либу, пригодную для промышленного применения - буду рад про неё узнать.

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

> Если кто-нибудь знает полноценную либу, пригодную для промышленного применения - буду рад про неё узнать.

В Qi посмотри, там оно в лучших традициях ;)

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

А можно ли выдрать оттуда отдельно pattern matching? Сам Qi мне не нравится и это не библиотека, а не слишком-то прозрачный другой язык поверх лиспа.

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

>lambda заменять на греческую лямбду. Хех, а если пойти дальше, можно заменять def в начале слова на дельту, а with - на омегу.
>Самое главное, что такое преобразование обратимо и не напрягает НИКОГО из читателей твоего кода - они получают лисп во всей его чистоте.


"боян"
http://www.cs.berkeley.edu/%7Eharmonia/harmonia/projects/harmonia-mode/doc/in...

http://www.cs.berkeley.edu/%7Eharmonia/harmonia/projects/langs/index.html

> И есть ведь ещё тема "лисп как препроцессор для Java" и эта тема даже куда как более плодотворна, ведь можно и байт-код генерить.


повозился немного с MBase. Работает! Довольно нормальные примеры.

На лисповом ядре реализованы лексер в AST, pattern matching, пролог. В примерах есть типизация Хиндли-Милнера, хаскелеподобный DSL и т.п.

На реализованных DSL множество озвученных проблем уходит. Например, notnet язык интегрирующийся в .NET, синтаксис вроде C# в скобках, наподобие nuLisp с ObjectiveC. Например, System@String#Concat = System.String.Concat и т.п. В примерах есть например генерация OpenGL шейдеров , что-то вроде линковки gl/glut функций в пространства имен макрами с pattern matchingom

Любопытный компилятор компиляторов, и довольно функциональный "из коробки". Увы, под .NET и нет исходников; генерации регистрового байткода вроде LLVM "из коробки" нет (хотя есть пример для 3 регистров раскрашивания графа).

Из недостатков: нет исходников, примеры выбрасывают execptionы в .NET Framework (например, с региональными настройками "число" русскими не работает парсер чисел, с английскими -- работает). По идее должно работать под Mono.

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

через LLVM код во всё наверно можно генерировать в 2 подхода: экспортировать AST в LLVM или запустить AST под компилятором Схемы в LLVM (тут правда придется что-то дописать для раскрутки этой Схемы)

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

> Мне некогда писать свой asdf, автодокументатор, pattern matching и всё такое прочее. У меня, в крайнем случае, есть время почитать вылизанную доку по ним.

как идея: взять что-то встраиваемое в .NET или JVM, и реализацию каких-то вещей оттуда. Сделать на чём-то вроде MOP instrumentation framework (что-то вроде DTrace), чтобы можно было отпрофилировать и заменить на лету реализацию на другую, более эффективную. То есть использовать "из коробки" возможности платформы, и перекрыть своей более эффективной реализацией самые узкие места. После прототипирования когда решение более-менее нормально работает избавиться от стандартной платформы вроде .NET/JVM своей собственной (или из реализации лиспа).

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

> inux_org_ru, помоему, у меня в профайле есть мыло. Нет? Джаббером я не пользуюсь, поэтому и постучать в него не могу :)

Я его не вижу и похоже его видишь только ты.

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

В теме "[Lisp]как препроцессор для C - 2" ты придерживаешься точки зрения, весьма сходной с моей (хотя различия могут быть).

www_linux_org_ru ★★★★★
()

Re: [Lisp]как препроцессор для C - 2

Так, в общем, я вряд ли буду поддерживать эту тему в ближайшее время. См. новую тему.

den73 (*) (17.09.2008 12:39:13)

________________________________________________

А если я хочу отвечать на вопросы, поднятые в старой теме, тогда что?

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

эхм. 

(concatenate 'string "bud" "den73" 
(make-string 1 :initial-element #\@) (reverse '(#\u #\r #\. #\l #\i #\a #\m)))

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

> анонимус, вы ведь у меня за спиной не стояли и в экран мне не смотрели? Ступайте лесом...

Ты совсем туп, если спрашиваешь чё-то на форуме, где никто лучше тебя не знает, что же там находится, у тебя на экране :D Вобщем, как я и подозревал - ты гнусный троллюга.

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

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

Действительно нарушает, и предположу что это действитльно надо -- ибо иначе функциональщину не развести. Решение -- синонимы, причем не только столь простые. Вопрос только в том, почему синонимы вдруг в емаксе, а не в ридере, где это уместно? (Предположу, что ридер под это не заточен -- и это надо исправлять)

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

> Действительно нарушает, и предположу что это действитльно надо -- ибо иначе функциональщину не развести.

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

#:анонимус, если зарегишься, объясню, почему именно ты из нас двоих - лох. Кстати, совет сходить лесом - не такой уж недружелюбный. Я сам вчера там был - грибы и ягоды там есть, а комаров нет.

www_linux_org_ru, я ответил в теме "lisp как препроцессор для С - 2"

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

> Вопрос только в том, почему синонимы вдруг в емаксе, а не в ридере, где это уместно? (Предположу, что ридер под это не заточен -- и это надо исправлять)

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

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

Так, похоже, все отсюда ушли, но я вспомнил ещё одну гадость. Которая ясно показывает несостоятельность лиспа как языка общего назначения. loop facility... Которая вообще-то не lispy way. Т.е., для задачи общего назначения (итерация) сделали DSL, нарушающий базовые принципы лиспового синтаксиса. И включили его в стандарт (а не iterate, к примеру). Этот факт говорит о многом...

Другой стандартный оператор цикла do настолько ужасен, что я до сих пор им не могу пользоваться без чтения мануала.

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

Ну и уж если об этом говорить, то скажу и про iterate. Ещё одна недоделанная библиотека. В loop "ключевые слова" могут быть из любого пакета и это правильно. В iterate есть какие-то дурацкие ограничения на пакеты. Когда я попытался использовать iterate совместно с пакетом, экспортирующим символ for, у меня начались проблемы. В итоге, я отказался от iterate (который гораздо лучше) и вернулся к loop.

Конечно, эту проблему легко пропатчить, но это до сих пор не сделано.

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