LINUX.ORG.RU

Какашки в Common Lisp


7

4

Предлагаю учёным мужам в этом топике собрать и обсудить проблемы в языке Common Lisp. Кому что не нравится?

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

Не нравится неполная интеграция CLOS в язык: распознавание класса в CLOS для стандартных лисповских типов ещё работает, но не для своих типов, объявленных через deftype.

Ну и вообще CLOS жирноват для 90% задач. Не говоря уж про MOP, который почти никем не используется, а если и используется, то для решения проблем с кривостями CLOS, либо просто книжку AMOP обчитался и повредился умом.

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

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

loop - какашка. Это не лисп. Точка.

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

unwind-protect - хорошо, но от попыток человеком сэмулировать продолжения для CL хочется икать. Такие trade-off вполне понятны, но лучше бы unwind-protect ограничили.

Ну и более мелкие ляпы в стандарте, типа (elt sequence index), но (nth index list).

Да, этот пост написан в Емаксе, запущенно под лисповым оконным менеджером человеком, получающем деньги за написание лиспокода :)

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

Макрос даже не обязательно должен быть функцией. Единственное требование - его можно _использовать_ в качестве функции, которая принимает АСТ и возвращает АСТ (как АСТ представлено - вообще не важно). Вот макрос может быть чем угодно, что удовлетворяет такому требованию.

Понятно, что АСТ можно как угодно представить (списки, или более точно), а макросы можно как угодно реализовать. Я говорю о _естесвенном_ (если угодно - правильном) представлении. И видеть реализацию такого представления можно где угодно - хоть в CL (где вместо АТД s-выражения), хоть в Haskell, хоть в Nemerle (с точными АТД).

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

> Это разделение не строгое, оно только означает, что функции первого вида _как правило_ работают в runtime, а второго и третьего _как правило_ в compile-time.

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

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

> Haskell

Ну с хаскелем вообще разговор особый - это сам по себе макроязык. Единственные, теоретически возможные программы, которые можно написать на хаскелле - это программы, которые генерируют другие программы :)

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

костыльный шизофренический бред обдолбавшегося галлюциногенами идиота.

Это ты схемер?) Рубишь сук на котором сидишь, так как это бред, в том числе, Гая Стила.

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

Ну у CL вообще разницы между рантаймом/компайлтаймом нету

Разница есть, это в CLHS прописано. Просто раскручивать этот процесс (r->c->r->c->...) можно сколько угодно. У любой ОС кстати так же - если не так (нет полной раскрутки), то нельзя запустить компилятор в рантайме и работать будет только то что есть в коде ядра, чтобы было что-то ещё нужно его дописать (либо дописать до возможности полной раскрутки).

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

Макросы - типы, функции - значения.

единственная информация компилятору о типе переменной - это в какой ветке вычислений эта переменная стоит

Ну с хаскелем вообще разговор особый - это сам по себе макроязык.

Вот это совсем непонятно - можешь объяснить?

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

> Макросы - типы, функции - значения.

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

(if (integer? x) (...) (...)) знаем, что в первой ветке х - integer, во второй - соответственно он integer быть не может. Но это плохой пример, лучше: (if (< (length x) 10) (...) (...)) соответственно в первой ветке х имеет тип списка с количеством элементов < 10, во второй - дополнение к этому типу. Если у нас несколько if, то, понятно, надо типа пересекать. + отслеживаем data-flow, чтобы знать, под какими предикатами может стоять х в данной точке (если он из других ф-й прилетел).

Ну с хаскелем вообще разговор особый - это сам по себе макроязык.

Ну что возвращает любая программа на хаскеле? то, что возвращает main. А что возвращает main? Всегда - IO. А что такое IO? Это вычисление. Программа - представление вычисления, значит, любая порграмма на хаскелле возвращает программу. Возвращает чисто и без сайд-эффектов :) Ну а кто потом выполняет эту программу - дело десятое уже, тут хаскель не пределах (формально можно вообще считать, что IO - это строки выражений на некотором конкантенативном ЯП, а bind просто выполняет конкантенацию). То, что все полезные действия происходят именно при выполнении этой результирующей программы - никому не важно.

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

> Рубишь сук на котором сидишь, так как это бред, в том числе, Гая Стила.

У нас в Racket такого бреда нет - вместо него няшные фазы.

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

> Разница есть, это в CLHS прописано.

Ну формально она, может, и есть, а по факту нет. Если неймспейс при компиляции и рантайме один - то какая же тут разница?

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

> Ну что возвращает любая программа на хаскеле? то, что возвращает main. А что возвращает main? Всегда - IO. А что такое IO? Это вычисление. Программа - представление вычисления, значит, любая порграмма на хаскелле возвращает программу. Возвращает чисто и без сайд-эффектов :)

Кстати, а это объяснение где-то в сети есть, или это местный фолькЛОР?

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

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

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

> Мсье, ваш Racket - говно.

Но что можно сделать, мсье? Все - говно, и приходится его жрать, выбор лишь в том, чтобы жрать то, которое менее запашисто. CL - чересчур запашист.

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

> А в каком пункте возникает сомнение?

Ни в каком, отличное объяснение. Вижу его на ЛОР уже второй или третий раз, но в других местах не встречал.

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

> .. CL .. вся макросистема - костыльный шизофренический бред

обдолбавшегося галлюциногенами идиота. ..

Мсье, ваш Racket - говно.



В общем, славное братство anonymous-ов никогда не упустит возможности продемонстрировать, что в лиспе говно вместо сообщества.

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

А в какой стране молодежь приходит на работу и приносит с собой Лисп?

В Бразилии и ОАЭ (по-моему).

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

Но что можно сделать, мсье? Все - говно, и приходится его жрать, выбор лишь в том, чтобы жрать то, которое менее запашисто. CL - чересчур запашист.

Для кого-то - засохший и вонючий сыр с плесенью, а для кого-то - выдержанный не менее 22 месяцев деликатес.

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

Только у этого «объяснения» терминология хромает, а по сути верно. Значение main возвращает вычисление IO, которое затем исполняется. И за счет ленивости нет разделения на две фазы: возвращение самого вычисления и его исполнение происходят одновременно.

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

> Ну что возвращает любая программа на хаскеле? то, что возвращает main. А что возвращает main? Всегда - IO. А что такое IO? Это вычисление. Программа - представление вычисления, значит, любая порграмма на хаскелле возвращает программу. Возвращает чисто и без сайд-эффектов :) Ну а кто потом выполняет эту программу - дело десятое уже, тут хаскель не пределах (формально можно вообще считать, что IO - это строки выражений на некотором конкантенативном ЯП, а bind просто выполняет конкантенацию). То, что все полезные действия происходят именно при выполнении этой результирующей программы - никому не важно.

Во-первых, main не возвращает ничего. main уже само по себе готовое IO. Это не функция.

Во-вторых, IO — это не вычисление, а инструкции по работе в внешним миром, если уж пользоваться такой интерпретацией.

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

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

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

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

А если так? :)

class foo(object):
    def __init__(self):
        self.__private_bar = None

f=foo()
print(f._foo__private_bar)

Вы думаете, что в С++ так сделать нельзя? или, может, думаете, что от const никак не избавиться?.. да всё можно, только это называется - ССЗБ

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

А если там несколько if...elif...elif?

bad design же

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

> за 20

В том то и проблема, что за 30.

обоснуйте

Ну, дык, ракеты это единственное, что у нас ещё получается нормально делать.

4.2 лютый песец что творится, просто «ТАМ» ещё хуже :)

А у американцев временная проблема просто.

ну да, ну да :)

И они на наших ракетах летают, но свою начинку не дают (а наша говно).

поверьте, ихняя ещё большее говно :)

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

> Вижу его на ЛОР уже второй или третий раз, но в других местах не встречал.

Гм. Я его как раз и писал здесь два или три раза :) Сам тоже такого объяснения не встречал, обычно просто говорится, что монада - абстракция цепочки вычисления, но не делается никаких выводов о семантике ИО. А в «официальных» источниках обычно ИО поясняется через протаскивание World. Видимо, любителям хаскеля некомфортно признавать, что их язык по сути не определен до тех пор, пока мы не специфицировали исполняющий ИО рантайм (каковая спецификация, по идее, и будет _настоящей_, семантикой Хаскеля, с энергичными вычислениями и сайдэффетками).

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

> В общем, славное братство anonymous-ов никогда не упустит возможности продемонстрировать, что в лиспе говно вместо сообщества.

А то! Мы, Лисперы, всегда готовы макнуть в говно ближнего своего.

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

>> В том то и проблема, что за 30.

обоснуйте


Я спрашивал тех самых «зубров», они отвечали однозначно - с самого начала 80-ых пошло резко сокращение финансирования и сворачивания большинства исследовательских программ - в стране тупо кончились деньги.

поверьте, ихняя ещё большее говно :)


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

archimag ★★★
()

Exceptional programmers are often attracted to Lisp. It may be that Lisp helps very talented programmers accomplish more. Lisp imposes almost no structure, and that could be attractive to highly creative people. More typical programmers might benefit from languages that provide more structure.

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

> Во-первых, main не возвращает ничего. main уже само по себе готовое IO. Это не функция.

Во-вторых, IO — это не вычисление, а инструкции по работе в внешним миром, если уж пользоваться такой интерпретацией.

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

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

Ну это вообще не при чем.

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

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

Черт, а вот для меня это все крайне разные вещи. Да и зачем называть main функцией, если она не принимает аргументов? Может лучше скаляром?

Ну это вообще не при чем.

Ну тогда могу еще придраться к тому, что bind никакой «конкатенации» не выполняет :) И даже интерпретировать его так не получится. Откуда «конкатенация» в (a -> m b) -> (m a -> m b)?

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

> я вот лично не вижу разницы между константой и функцией 0 аргументов

Если сайд эффектов нету в функции, то возможно оно так и есть. Но как только в функции возникают сайд эффекты - разницы будет громадной. Или же если работа функции будет замкнута на переменную.

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

> (...) я вот лично не вижу разницы между (...) вычислением и последовательностью инструкций (...)

Фу-у-у, императивщик.

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

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

Разница, тем не менее, наличествует.

Значение можно рассматривать как функцию, результат которой мемоизируется. Мелочь, а меняет очень многое.

Что касается вычислений, то последовательность действий может быть запросто обратной. Например, можно «перевернуть» монаду State и состояние будет передаваться тогда из конца в начало. Но такое возможно только в ленивом языке.

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

Ни разу в жизни не писал факториала на хацкеле. Если даже и было когда-то, то давным давно забыл.

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

> Значение можно рассматривать как функцию, результат которой мемоизируется. Мелочь, а меняет очень многое.

Результат вычисления все равно тот же (сайд-эффектов ведь нет), так что не меняет.

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

> И за счет ленивости нет разделения на две фазы: возвращение самого вычисления и его исполнение происходят одновременно.

Нет-нет, мы же не идиоты исполнять их одновременно? Лучше сперва вычислить все значения в программе на хаскеле во время компиляции, а потом уже только исполнять main (то есть результат).

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

> Нет-нет, мы же не идиоты исполнять их одновременно? Лучше сперва вычислить все значения в программе на хаскеле во время компиляции, а потом уже только исполнять main (то есть результат).

Конпелятор GHC настолько умен, что разницы с мейнстримовыми языками особой нет. Вычисление в монаде IO конструируется на ходу и исполняется обычно так же быстро, как и исполняется совершенно аналогичный императивный код на какой-нибудь яве или c# без всяких там заморочек с монадами и функциями. Загадка из загадок.

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

> Результат вычисления все равно тот же (сайд-эффектов ведь нет), так что не меняет.

Space complexity совершенно иная. Меняет.

P.S. в прошлый раз не подписался

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

Так ведь кроме main мы можем в компайлтайме вообще выполнить все не-ИО функции. Например f = g ..., где g - какаято сложная функция, а потом main = return f логично f вычислить при компиляции. А конструирование монады, конечно же, на производительность не влияет, потому что на практике никакой монады не конструируется.

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

В GHC до черта оптимизаций. Им можно также гордится, как и компилятором SBCL. Мне нравятся оба :)

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

// А как это мешает «спорить о высоком»?

а, не обращайте внимания, это у меня трололо опухло

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

Я спрашивал тех самых «зубров», они отвечали однозначно - с самого начала 80-ых пошло резко сокращение финансирования и сворачивания большинства исследовательских программ - в стране тупо кончились деньги.

ну да, как кончились деньги так и запустили энергию-буран

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

спутники - да, но Вы спутники не путайте с «ракетами»

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

> Это единица с санкой :)

WHNF?

Так ведь кроме main мы можем в компайлтайме вообще выполнить все не-ИО функции.

Тогда уточни это утверждение, пожалуйста. А то я не понимаю тебя.

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

> WHNF?

Ну (cons 1 (lambda ...))

Тогда уточни это утверждение, пожалуйста. А то я не понимаю тебя.

не понял что уточнить? Мы значение вычислили - это единица и функция, вычисляющая rest. В данном случае ф-я - это значение, ее дальше вызывать не надо. Так же как f x = x, тут f - функция, мы ее саму (функцию) вычисляем, но не вызываем.

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