Здравствуйте, eao197, Вы писали:
Д>>А с чего ты взял, что "без гвоздей" — это именно Лисп, а не С++?
E>Фокус в том, что на место "без гвоздей" можно поставить любой язык.
Разоблачаем фокус — аналогия про плотника не годится для сравнения Лиспа и С++.
E>Если Lisp так хорош, да еще и появился бог знает когда, да еще и развивался в лучшую сторону все это время, то почему мы работаем с C/C++, Java, C#, Perl, VB?
Потому что массы предпочитают то, что проще.
E>И не маловажными факторами против C++ являются его сложность и высокие требования к квалификации членов команды. Я сам сталкиваюсь с тем, что сейчас проще найти Java и C# программистов, чем C++.
Так ведь все технологии развиваются до уровня Лиспа. Вводится GC, closures, метапрограммирование. Соответственно, и требования будут расти всё равно.
И так пока не получится Лисп, ну или Dylan, если синтаксис вложенных списков не нравится.
Здравствуйте, eao197, Вы писали:
E>Только практика показала, что языки, которые требуют серьезной смены сознания (я сталкивался с Lisp и Prolog, чуть-чуть Smalltalk), широкого применения не получают. Вероятно из-за того, что далеко не все хотят менять свое сознание. И имеют на это право.
Необразованные мужики тоже имели право махать топором, а по праздникам бухать и бороться.
Но их не спрашивали, потому что глупые и ничего не понимают. Ввели образование обязательное. Не насильно, но так, что образованный имел больше возможностей.
В результате имеем множество гораздо более умных людей, чем были крестьяне 200-300 лет назад. Которые изобрели компьютеры, интернет, и вообще продвинулись вперёд. Личное развитие никогда не было во вред, как в масштабах одной личности, так и в масштабах страны.
Здравствуйте, eao197, Вы писали:
E>Я исхожу из того, что Lisp не получил такого широкого распространения, как мейнстримовые языки и технологии. Для меня главной причиной этого является как раз "заумность" Lisp-а, которая отталкивает от него начинающих, да и не только программистов.
По своему опыту: в свое время с потока 2-го курса, курс ФЛП (Prolog + Lisp) "оттолкнул" человека 2-3... C/C++ "оттолкнул" гораздо большее кол-во. Заумностью там и близкр не пахнет. Такая формализация нам может только сниться. В свое время, помниться, мы — молодые и зеленые — офигивали от осознания того, что все "навароты", оказывается, можно выразить лишь "одними скобками".
Здравствуйте, jedi, Вы писали:
J>Здравствуйте, pvgoran, Вы писали:
P>>IMHO это вполне возможно. Например, мне очень не хватает closures в С++, и мне думается, что они вполне могли бы заметно поднять качество кода во многих случаях.
J>boost::function<> не устраивает по религиозным причинам?
Причем здесь религия... Я использую и ценю boost::function+boost::lambda, но по сравнению с "нормальными" closures это вещь достаточно ограниченная и очень многословная. А уж как "удобно" их отлаживать (и в compile-time, и в runtime)...
Здравствуйте, <Аноним>, Вы писали:
А>>>Подобная либа есть -- http://www.cliki.net/TypeL
P>>Посмотрел, впечатлился. Правда, моих знаний не хватило, чтобы понять, будет ли оно работать при компиляции.
А>В принципе, ничего не мешает подобной вещи быть компилируемой.
Т.е. есть возможность "навешать" на компиляцию какие-нибудь hook'и, которые проследят за всем чем надо?
P>>А вообще — я так понимаю, чтобы такая библиотека работала в реальных приложениях, P>> нужно описать типы библиотечных функций. Невеселая перспективка... P>>(если только это уже не сделано и не хранится где-то в удобном формате).
А>В детали либы не вглядывался, но, думается мне, это не обязательно.
В общем-то да... Type inference с этим, наверное, может справиться для большинства библиотечных функций.
А>GUI есть -- пожалуйста, CommonWindows/CAPI, или open-source, пусть менее документированные Cells-Gtk, А>McCLIM (для "попробовать" последние два, думаю, также подойдут).
Посмотрю...
А>>>Я хочу сказать, А>>>что победа над некоторыми ошибками, достигаемая строгой типизацией, является Пирровой, А>>>и неудобства, ей причиняемые, перевешивают её преимущества.
P>>Вот это уже более понятно... Хотя и не-особенно-легко-проверяемо.
А>Проверить проще всего, попробовав.
Здравствуйте, Кодёнок, Вы писали:
E>>Если Lisp так хорош, да еще и появился бог знает когда, да еще и развивался в лучшую сторону все это время, то почему мы работаем с C/C++, Java, C#, Perl, VB?
Кё>Потому что массы предпочитают то, что проще.
Вот именно. И это "медицинский факт".
... << RSDN@Home 1.1.4 stable rev. 510>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, Аноним, Вы писали:
А>2. Учиться. Если у Вас есть немного свободного времени, потратьте его часть на изучение А>языков, которые заставляют человека _думать по другому_. Изучите Lisp, Prolog, Haskell, А>SML, Smalltalk, Erlang (особое внимание стоит уделить Common Lisp'у, как языку А>расширяемому и наиболее практичному). Не давайте мозгам заржаветь, учитесь мыслить шире. А>Для начала, это поможет Вам стать хорошим программистом, даже если на хлеб себе вы будете А>зарабатывать, программируя на других языках. Все мейнстримные языки построены, А>как правило, по принципу "те же яйца, вид сбоку". Осознайте, что мир на самом деле А>не сошёлся на лежащем в их основе наборе стандартных парадигм.
Какую реализацию Lisp-а под Win посоветуете ? Желательно наличие возможности вызова внешних функций написанных на С++.
Здравствуйте, bkat, Вы писали:
B>Интересный топик. B>Только вот перенос его в философию программирования B>сделал невозможным участие анонима в обсуждении...
Я тут — но в данный момент я занят. Позже изложу
некоторые мысли, а пока работать надо
З.Ы. Анонимно писал, т.к. было лениво регистрироваться.
Здравствуйте, eao197, Вы писали:
E>>>Потому, что объем (даже не сложность, а простой объем) задачи полностью нивелирует разницу в профессиональном уровне матерого плотника и начинающего строителя.
Д>>чушь. читаем классиков — Брукса, например. Или хотя бы Сполски.
E>Что именно? Что именно чушь? Что именно читаем (хотя бы конкретную главу, а лучше цитату)?
Книги нет сейчас рядом, поэтому точно не скажу. Можно поискать в той главе, в которой рассматривается организация рубочих групп. "Операционная бригада", вроде бы — но могу и ошибаться. А чушь была в слове "нивелирует" — разница в производительности между "матерым" программистом и начинающим составляет разы или даже порядки, и чем объемнее задача, тем больше становится разница (за исключением тех случаев, когда задача легко и четко разбивается на части)
E>А Сполски уже классик?
Ну я и написал "хотя бы Сполски", если нет под рукой классиков
Здравствуйте, pvgoran, Вы писали:
P>Т.е. есть возможность "навешать" на компиляцию какие-нибудь hook'и, которые проследят за всем чем надо?
Ну так макрос по сути — этьо обычная функция, преобразующая AST->AST. Ничто не мешает ей использовать любые доступные алгоритмы для анализа этого самого AST (в том числе и алгоритмы проверки типов).
Здравствуйте, WFrag, Вы писали:
WF>Здравствуйте, pvgoran, Вы писали:
P>>Т.е. есть возможность "навешать" на компиляцию какие-нибудь hook'и, которые проследят за всем чем надо?
WF>Ну так макрос по сути — этьо обычная функция, преобразующая AST->AST. Ничто не мешает ей использовать любые доступные алгоритмы для анализа этого самого AST (в том числе и алгоритмы проверки типов).
Вопрос был, можно ли заставить систему делать это при компиляции, а не при выполнении.
Здравствуйте, pvgoran, Вы писали:
P>Здравствуйте, WFrag, Вы писали:
WF>>Здравствуйте, pvgoran, Вы писали:
P>>>Т.е. есть возможность "навешать" на компиляцию какие-нибудь hook'и, которые проследят за всем чем надо?
WF>>Ну так макрос по сути — этьо обычная функция, преобразующая AST->AST. Ничто не мешает ей использовать любые доступные алгоритмы для анализа этого самого AST (в том числе и алгоритмы проверки типов).
P>Вопрос был, можно ли заставить систему делать это при компиляции, а не при выполнении.
Тебе и говорят, что компиляция от выполнения по сути процессов не отличаются, т.е. там выполняются примерно теже действия, просто в одном случае это функции defun, а в другом макросы лиспа defmacro (не путать с сишными макросами), теже самые функции, только развёртывающиеся не в рантайме (хотя есть интерпретаторы в которых разворот макросов идёт в рантайме, но это отдельная история)
Здравствуйте, pvgoran, Вы писали:
P>Здравствуйте, WFrag, Вы писали:
WF>>Здравствуйте, pvgoran, Вы писали:
P>>>Т.е. есть возможность "навешать" на компиляцию какие-нибудь hook'и, которые проследят за всем чем надо?
WF>>Ну так макрос по сути — этьо обычная функция, преобразующая AST->AST. Ничто не мешает ей использовать любые доступные алгоритмы для анализа этого самого AST (в том числе и алгоритмы проверки типов).
P>Вопрос был, можно ли заставить систему делать это при компиляции, а не при выполнении.
И ещё — здесь проявляется одна из особенностей лиспа, где код=данные, т.е. над кодом можно выполнять все действия, которые можно выполнять над данными.
Здравствуйте, Курилка, Вы писали:
WF>>>Ну так макрос по сути — этьо обычная функция, преобразующая AST->AST. Ничто не мешает ей использовать любые доступные алгоритмы для анализа этого самого AST (в том числе и алгоритмы проверки типов).
P>>Вопрос был, можно ли заставить систему делать это при компиляции, а не при выполнении.
К>Тебе и говорят, что компиляция от выполнения по сути процессов не отличаются, т.е. там выполняются примерно теже действия, просто в одном случае это функции defun, а в другом макросы лиспа defmacro (не путать с сишными макросами), теже самые функции, только развёртывающиеся не в рантайме (хотя есть интерпретаторы в которых разворот макросов идёт в рантайме, но это отдельная история)
Да, действительно, тут я затупил... Если уж тело функции (которое есть аргумент defun) обрабатывается при компиляции, то скорее всего можно делать то же самое и с аргументом какого-нибудь deftypel.
Кстати, а подобные трюки (преобразования кода/AST) не мешают отладчику понять, какой исходный код соответствует данному исполняемому коду?
Здравствуйте, pvgoran, Вы писали:
P>Кстати, а подобные трюки (преобразования кода/AST) не мешают отладчику понять, какой исходный код соответствует данному исполняемому коду?
Извини, не могу понять, в чём вопрос? По сути у тебя получается рекурсия, в нормальных условиях конечная (и скорее всего ограничивающаяся 1 уровнем), т.е. макрос у тебя может генерировать или другой макрос или код, который и даёт нам итоговый бинарник. Думаю, что можно маркосы зациклить, но в данном случае программист — сам себе злобный буратино, хотя может быть это и обрабатывается какими-либо компиляторами (т.е. честно признаюсь — не ставил такой задачи и проверять желания особо нет )
Получается, что если отвечать на твой вопрос, то у нас есть 2 вида "функций" — 1) просто функции, т.е. уже содержащие итоговый код; 2) функции, которые нужно дальше "разворачивать", чтобы получать функцию с итоговым кодом, т.е. это макросы.
Надеюсь, что сильно не наврал
Да интересная дискуссия, даже зарегился на RSDN, чтоб сюда запостить.
С Лиспом я знаком года 2-3, с тех пор как плотно начал юзать емакс, но именно CL, ну и схемой, заинтересовался только в конце прошлого года. Сначала прочитал, правда не до конца, первый том "Мир Лиспа", как то мне не очень понравилось и я забил, так что не советую вам её читать, очень скучно плюс только в том, что про Common Lisp это единственная книга на русском. Потом, когда появилась в инете Practical Common Lisp, и я его прочитал, да ещё открыл для себя SLIME, всё стало намного интереснее. Язык ИМХО самый навороченный из всех, и причина этому именно макросы в сочетании с простым представлением программ и данных. Чего стоят те же макросы loop & format.
Вы тут обсуждали отсутствие стат. типизации, я вспомнил про declare, хотя это не совсем то, но во первых она выдаёт варнинги при компляции, если при вызове указан не тот тип + ускоряет выполнение, не то что вам нужно? Только конечно это не распространяется на стандартные функции. Я написал небольшой макрос, который делает возможным быстрое объявлении функций, с заданным типом аргументов.
(defun test (b a)
(declare (string b) (integer a))
(format t "~a have ~d apples." b a))
я могу писать так:
(defun-declare-type test ((string b) (integer a))
(format t "~a have ~d apples." b a))
И при создании функции, с не правильным типом второго аргумента в вызове test:
(defun-declare-type test2 ((string a) )
(test "ABC" a))
Выдаётся варнинг:
In: DEFUN-DECLARE-TYPE TEST2
; (TEST "AA" A)
; ==>
; A
; Warning: Result is a BASE-STRING, not a (VALUES &OPTIONAL INTEGER &REST T).
;
; Compilation unit finished.
; 1 warning
совсем маленькое улучшение, но оно показывает, как легко в язык добавляются новые конструкции, причём по нажатию М-. или во время отладки я всёравно попадаю на определения этой функции.
Можно привести пример посложнее из PCL, макрос генерирует класс бинарных данных:
Уже сложнее, но зато получается очень хорошая абстракция, не говоря уже об уменьшении объёма кода.
И именно благодаря столь-удачному подходу к макропрограммированию CL можно ИМХО назвать самым мощным ЯП общего применения.
Ещё мне очень нравиться скорость выполнения, с учётом дин. типизации.
Я как-то переписывал одну вычислительную программку с Python — на CL, так вот при использовании компиляторов CMUCL или SBCL скорость выполнения возросла в 4-5 раз, при примерно одинаковом количестве кода. В CL можно было бы сделать оптимизацию, и тогда бы скорость наверное возросла ещё в несколько раз, но мне было лень.
Ну и конечно REPL + инкрементальная компиляция очень сильно облегчает (можно сказать делает более увлекательным что-ли ) написание и тестирование программ.
Тем кому не нравятся скобки могу ответить, что нужно юзать структурное кодирование, парные скобки вставляются автоматически, и с помощью С-М- комбинаций можно легко передвигаться по сколь-угодно сложным спискам. То есть скобки здесь это огромны плюс.
Вот напримерпример есть функция:
Курсор стоит на место каре, хочу я добавить let к этому выражению,
нажимаю два раза С-M-U(ctrl-alt-u), курсор переноситься на два уровне вверх, т.е. перед скобкой, стоящей перед плюсом. потом нажимаю M-1 ( скобки автоматом добавляются как в начале так и в конце:
При таком подходе намного реже требуется пользоваться стрелками, потомучто мы работаем не с последовательностью знаков, а с вложенными списками и лисп-символами, т.е. над более высокими абстракциями. к тому же префикс C-M- для удобства можно заменить просто на C-.
Можно говорить очень много об отдельных мегафичах CL, таких как например CLOS, но это отдельные и очень объёмные темы.
Так что всё-таки всем советую прочитать хотя-бы Practical Common Lisp, чтобы понять все преимущества Лиспа.
Ну и напоследок хочу сказать что мне не нравиться. Так как стандарт создавался почти 20 лет назад, а он основывался на намного более ранних разработках, в нём присутствует достаточное количество небольших несогласованностей, как например порядок аргументов в функциях доступа к n-ому элементу массива и списка, или невнятные названия некоторых стандартных функций, или атавизмов, как ключ &aux в определении функций. Но в принципе это не играет особой роли при разработке.
Здравствуйте, Курилка, Вы писали:
К>Здравствуйте, pvgoran, Вы писали:
P>>Кстати, а подобные трюки (преобразования кода/AST) не мешают отладчику понять, какой исходный код соответствует данному исполняемому коду?
К>Извини, не могу понять, в чём вопрос? По сути у тебя получается рекурсия, в нормальных условиях конечная (и скорее всего ограничивающаяся 1 уровнем), т.е. макрос у тебя может генерировать или другой макрос или код, который и даёт нам итоговый бинарник. Думаю, что можно маркосы зациклить, но в данном случае программист — сам себе злобный буратино, хотя может быть это и обрабатывается какими-либо компиляторами (т.е. честно признаюсь — не ставил такой задачи и проверять желания особо нет ) К>Получается, что если отвечать на твой вопрос, то у нас есть 2 вида "функций" — 1) просто функции, т.е. уже содержащие итоговый код; 2) функции, которые нужно дальше "разворачивать", чтобы получать функцию с итоговым кодом, т.е. это макросы. К>Надеюсь, что сильно не наврал
Во время компиляции в CL макросы ПОЛНОСТЬ рекурсивно разворачиваются до примитивов очень низкого уровня.
Вот пример подсчёт кубов чисел до тридцати больших 1000:
(loop for i upto 30 for q = (expt i 3) when (> q 100) summing q)
Здравствуйте, Курилка, Вы писали:
P>>Кстати, а подобные трюки (преобразования кода/AST) не мешают отладчику понять, какой исходный код соответствует данному исполняемому коду?
К>Извини, не могу понять, в чём вопрос? По сути у тебя получается рекурсия, в нормальных условиях конечная (и скорее всего ограничивающаяся 1 уровнем), т.е. макрос у тебя может генерировать или другой макрос или код, который и даёт нам итоговый бинарник. Думаю, что можно маркосы зациклить, но в данном случае программист — сам себе злобный буратино, хотя может быть это и обрабатывается какими-либо компиляторами (т.е. честно признаюсь — не ставил такой задачи и проверять желания особо нет )
Рекурсия макросов не предполагалась.
К>Получается, что если отвечать на твой вопрос, то у нас есть 2 вида "функций" — 1) просто функции, т.е. уже содержащие итоговый код; 2) функции, которые нужно дальше "разворачивать", чтобы получать функцию с итоговым кодом, т.е. это макросы.
Ну, во втором случае речь идет скорее о "вызовах" макросов.
Пример, иллюстрирующий вопрос:
(defmacro (my-transform code) .......)
(my-transform
(if (= x y)
(- x y)
666
)
)
(Сразу скажу — синтаксис defmacro не знаю.)
my-transform, допустим, добавляет в преобразуемый код вызовы, выводящие на экран названия (процедуры) перед каждым вызовом процедуры.
Так вот, получится ли в данном примере пройтись отладчиком по исходному коду, который внутри вызова my-transform?