На этот пост меня подвигли рассуждения Майкла Фогуса (автора "The Joy of Clojure") о том, что такое "программерская элита".
Фогус очень разумно объясняет, что не язык программирования является признаком "элитности" программиста. Даже Java может казаться сложной и непонятной тем, кто ее не знает. И даже Haskell будет простым и удобным тем, кто разобрался с этим языком.
Более того, действительно крутые программисты, с которыми Фогусу довелось иметь дело, работали даже с таким позорным убожеством, как С++, и тем не менее умудрялись быть очень-очень продуктивными.
Элитными могут быть, пожалуй, только программерские задачи, решить которые может лишь очень малый процент программистов. Т.е. не мега-навыки делают программиста "элитой", а, в первую очередь, крайне сложные проблемы, которые этот программист решает. Само собой, для решения сложных задач нужно иметь уровень профессионализма намного выше среднего, а также подходящие инструменты.
Выбор языка программирования для решения нетривиальных задач -- это уже следствие сложности самих задач. Язык программирования тогда "подходит" для задачи, когда упрощает ее решение, а не тогда, когда конкретный программист знает язык лучше или любит его больше. Clojure -- один из таких языков. Его "функциональность", макросы, гомоиконный синтаксис, STM, REPL, Swank -- все это предназначено для упрощения решения именно сложных задач.
Впринципе, согласен с тем, что написал Фогус. Clojure не просто располагает к экспериментированию, а прямо навязывает такой "экспериментаторский" стиль разработки. Вспомните, как нас учили программировать в школе и универе? Задачи часто решались на бумажке, нередко рисовали блок-схемы алгоритмов. Везде, где я работал, любили UML и много "планировали" перед тем, как приступить к кодированию. В Clojure -- все наоборот. Думать заранее, конечно, тоже нужно, но конспектируется "планируемое" решение не в блок-схемах или псевдокоде, а прямо на Clojure.
Т.е. вначале может и возьмешь бумажку с ручкой, но уже через минуту думаешь: "Какого чёрта?", открываешь Emacs, Slime REPL и пробуешь все уже там. Заработало? Сохраняешь в файл с исходником. Не заработало? Пробуешь дальше, не перезагружая программу. Все вычисленные данные, все переменные -- все остается; прямо в работающей программе можно переопределить любые функции и значения. Создается ощущение, что попал не просто в debug-режим, а будто только в таком режиме и работаешь.
На днях я экспериментировал с алогритмом Support Vector Machine, хотел научить классификатор по набору прилагательных от личать хорошие отзывы от плохих. С ресурса kinopark.by скачал все комментарии ко всем фильмам и рассортировал на два кластера: положительные отзывы и отрицательные (суммарно получилось окло 18Мб чистого текста). Выбрал все прилагательные (без окончаний) из каждого комментария; каждый комментарий закодировал дескриптором, содержащим 1 или 0 для каждого прилагательного из всего множества. Получился вектор размерностью около 10000. Вот такие-то вектора и скармливал классификатору на обучение.
Все это я делал только исключительно на Clojure. Все это, включая загрузку и разбор страниц с комментариями, заняло около 300 строк кода. За все время мне ни разу не потребовался дебаггер, и даже в голову не пришло писать unit-тесты (зачем, ведь функция каждый раз "пробуется" в REPL-е перед попаданием в исходник). И я не могу себе представить инструмента, более удобного для таких задач, чем Clojure.
Использованные библиотеки:
1.clj-http;
2.clj-tagsoup;
3.libsvm.
Фогус очень разумно объясняет, что не язык программирования является признаком "элитности" программиста. Даже Java может казаться сложной и непонятной тем, кто ее не знает. И даже Haskell будет простым и удобным тем, кто разобрался с этим языком.
Более того, действительно крутые программисты, с которыми Фогусу довелось иметь дело, работали даже с таким позорным убожеством, как С++, и тем не менее умудрялись быть очень-очень продуктивными.
Элитными могут быть, пожалуй, только программерские задачи, решить которые может лишь очень малый процент программистов. Т.е. не мега-навыки делают программиста "элитой", а, в первую очередь, крайне сложные проблемы, которые этот программист решает. Само собой, для решения сложных задач нужно иметь уровень профессионализма намного выше среднего, а также подходящие инструменты.
Выбор языка программирования для решения нетривиальных задач -- это уже следствие сложности самих задач. Язык программирования тогда "подходит" для задачи, когда упрощает ее решение, а не тогда, когда конкретный программист знает язык лучше или любит его больше. Clojure -- один из таких языков. Его "функциональность", макросы, гомоиконный синтаксис, STM, REPL, Swank -- все это предназначено для упрощения решения именно сложных задач.
Впринципе, согласен с тем, что написал Фогус. Clojure не просто располагает к экспериментированию, а прямо навязывает такой "экспериментаторский" стиль разработки. Вспомните, как нас учили программировать в школе и универе? Задачи часто решались на бумажке, нередко рисовали блок-схемы алгоритмов. Везде, где я работал, любили UML и много "планировали" перед тем, как приступить к кодированию. В Clojure -- все наоборот. Думать заранее, конечно, тоже нужно, но конспектируется "планируемое" решение не в блок-схемах или псевдокоде, а прямо на Clojure.
Т.е. вначале может и возьмешь бумажку с ручкой, но уже через минуту думаешь: "Какого чёрта?", открываешь Emacs, Slime REPL и пробуешь все уже там. Заработало? Сохраняешь в файл с исходником. Не заработало? Пробуешь дальше, не перезагружая программу. Все вычисленные данные, все переменные -- все остается; прямо в работающей программе можно переопределить любые функции и значения. Создается ощущение, что попал не просто в debug-режим, а будто только в таком режиме и работаешь.
На днях я экспериментировал с алогритмом Support Vector Machine, хотел научить классификатор по набору прилагательных от личать хорошие отзывы от плохих. С ресурса kinopark.by скачал все комментарии ко всем фильмам и рассортировал на два кластера: положительные отзывы и отрицательные (суммарно получилось окло 18Мб чистого текста). Выбрал все прилагательные (без окончаний) из каждого комментария; каждый комментарий закодировал дескриптором, содержащим 1 или 0 для каждого прилагательного из всего множества. Получился вектор размерностью около 10000. Вот такие-то вектора и скармливал классификатору на обучение.
Все это я делал только исключительно на Clojure. Все это, включая загрузку и разбор страниц с комментариями, заняло около 300 строк кода. За все время мне ни разу не потребовался дебаггер, и даже в голову не пришло писать unit-тесты (зачем, ведь функция каждый раз "пробуется" в REPL-е перед попаданием в исходник). И я не могу себе представить инструмента, более удобного для таких задач, чем Clojure.
Использованные библиотеки:
1.clj-http;
2.clj-tagsoup;
3.libsvm.
По статье согласен. Заинтересовал момент работы с Clojure. Насколько реально для вас сделать небольшой скринкаст и показать в действии робочий процес
ОтветитьУдалитьхотелось бы посмотреть исходники и попробовать реализовать тот же функционал, но на другом языке =)
ОтветитьУдалитьКстати, да, классная идея! А то мне все никак не удается объяснить непосвященным, что ж там такого крутого в этих лиспах! :-) Попробую сделать скринкаст.
ОтветитьУдалитьunel: зачем тебе исходники, если будешь писать на другом языке? :-) Пиши с нуля, ощутишь в полной мере, насколько сложно работать в традиционном стиле (write-compile-fix-compile-run-debug) по сравнению с тем, что есть в Clojure (Emacs, Slime, Swank).
ОтветитьУдалитьЕсли будешь делать скринкаст, то используй, пожалуйста, утилиту, чтоб на экране отображались вводимые комманды, а то после vim очень непривычен Emacs, хотелось бы посмотреть какие комбинации использует про. Заранее спасибо))
ОтветитьУдалитьОК, сделаю файл субтитров, на которых будут все команды Emacs.
ОтветитьУдалитьАлекс Отт тоже как-то писал об удобностях имакс и кложуры, но на скринкаст наверное пока нету времени.
ОтветитьУдалитьУ меня времени свободного тоже нет совсем. Именно поэтому лучше уж я один раз запишу скринкаст и раздам всем желающим, чем каждый раз буду устраивать live-сессию для демонстрации :-)
ОтветитьУдалитьОки, оки - заранее огромнейшее спасибо! Будем ждать
ОтветитьУдалитьВот скринкаст работы с ClojureScript REPL (http://vimeo.com/29535884)
ОтветитьУдалитьВот скринкасты про кложуру (решение небольших задачек): http://vimeo.com/channels/fulldisclojure
А вот screencast про Clojure/SLIME, etc. http://vimeo.com/9770382
Посмотрел последний скринкаст. В принципе -- да, то, что надо.
ОтветитьУдалитьРаз необходимость в демонстрации отпала, то свое запишу попозже, при случае.
А можно немного подробней непосредственно про классификацию прилагательных? Как отбирали среди всех слов именно прилагательные, как отсекали окончания, какой в итоге получился результат?
ОтветитьУдалитьНу тут уже не все так грандиозно. Алгоритм машины опорных векторов я вообще приплел сюда только по той причине, что на лекциях, которые я посещаю (A.I. Creates), дали задание "пощупать" SVM. На простых примерах libSVM отработал нормально, решил скормить ему задачку посложнее. На векторах большой размерности время обучения SVM уходит в бесконечность. Мое терпение лопнуло через пару часов обучения, и я не дождался результата.
ОтветитьУдалитьЕсли бы задача была не изучить SVM а действительно классифицировать отзывы, то, на мой взгляд, здесь проще взять Fuzzy Logic и посчитать, какая гипотеза более вероятная: положительная или отрицательная.
Окончания тоже выбирал "на глаз" из учебника. Если нужно более точно определить часть речи, то предлагаю обратиться к "Методам и алгоритмам трансляции естественно-языковых запросов к базе данных в SQL-запросы" Л.В.Найхановой и И.С.Евдокимовой. Там есть таблицы окончаний и еще много интересного. Книга доступна для скачивания в какой-то из электронных библиотек.
Ну, на самом деле, определение части речи зависит не только и не столько от окончаний, сколько от статистики их использования в контексте других слов. Хорошим мультиязычным инструментом для этого является TreeTagger (http://www.ims.uni-stuttgart.de/projekte/corplex/TreeTagger/). Это если будет интересно развить наработку :)
ОтветитьУдалитьА для SVM попробуйте линейное ядро - обычно количества прилагательных хватает, чтобы однозначно построить гиперплоскость без порождения дополнительных атрибутов. А время обучения чуть-чуть больше, чем для того же байевского классификатора (я так понимаю, вы его подразумеваете под нечёткой логикой).
А есть где-нибудь толковое описание алгоритма TreeTagger?
ОтветитьУдалитьНу, вот то, что есть прямо у них на странице:
ОтветитьУдалитьhttp://www.ims.uni-stuttgart.de/ftp/pub/corpora/tree-tagger1.pdf
http://www.ims.uni-stuttgart.de/ftp/pub/corpora/tree-tagger2.pdf
Из похожего есть ещё Stanford Dependency Parser (http://nlp.stanford.edu/software/lex-parser.shtml). А там уже литературы по теме сколько вагон и маленькая тележка.
Слушай, оставь контакт (е-мэйл или скайп). Хотелось бы пообщаться вне блога.
ОтветитьУдалитьandrei.zhabinski на гугломыле. В скайпе я реагирую гораздо медленней.
ОтветитьУдалить