2010-06-30

ASDF 2

Собираюсь написать серию постов про ASDF: его текущее развитие в связи с выходом ASDF 2, внутреннее устройство, шаблоны и некоторые идеи по поводу его использования. Вообще, в последние пару лет в Lisp-сообществе к этой теме (не только собственно ASDF, но и в целом управление сборкой и дистрибутивами), очень живой интерес, поскольку есть вопросы, которые требуют решения. Недавняя статья, дающая пищу для размышлений: Анализ использования ASDF в разных проектах.

ASDF является фактически единственным на данный момент сборщиком Common Lisp програм. Более того он играет свою роль в различных менеджерах дистрибутивов, хотя и не является самим по себе полноценным решением. И, я бы сказал, что со своей ролью инструмента сборки он справляется довольно неплохо, а вот в сфере описания дистрибутивов есть проблемы, которые пока что не решены на практике. Это заставляет многих людей, в том числе и меня, вообще не пользоваться подобными инструментами и произвоить установку дистрибутивов вручную (благо в Common Lisp среде, в том числе и благоаря ASDF это очень просто1), а других (в том числе и меня) задумыватся о создании собственного средства: примеры тому — Mudballs, Lispy, CL-Librarian, LibCL...

В недавней статье в журнале ПФП я написал, что
развитие средства управления пакетами должно идти именно с учетом децентрализованной структуры Лисп-среды, а не вопреки ей.

К такому же заключению мы пришли и в процессе обсуждения темы на форуме lisper.ru, которое также заставило меня немного заглянуть под капот ASDF, чтобы узнать, насколько реально и легко создать на его основе пакетный менеджер. Этот "быстрый взгляд" в итоге вылился в растянутое на целый месяц неспешное ковыряние кода и его доработку для полноценной поддержки версионирования. Свое решение я направил в список рассылки asdf-devel, однако оно вряд ли будет интегрированно. В любом случае, этой теме я собираюсь посвятить отдельную запись в этой серии.

А начнем мы с того, что нового нам несет ASDF 2, релиз которого состоялся 31 мая, и который уже скоро войдет в вашу любимую Лисп реализацию.

Целая новая версия системы претерпела существенный рефакторинг и доработку силами Фарэ и Роберта Голдмана. С точки зрения пользователей она включает в себя следующие улучшения (разумеется, накопленные и отлаженные за посление ряд релизов):
  • версионность самой библиотеки, возможность обновления ASDF

  • добавление более простого пользовательского интерфейса

  • добавление нового способа конфигурации

  • сохранение FASL-файлов отдельно (в других директориях) от исходного кода

  • улучшение работы c путями и соответствующее расширение классов component и system

  • исправление некоторых багов


Вот lightning talk Роберта на встрече TwinCity лисперов, посвященный ASDF 2. Нужно заметить, что ценность этого релиза не только практическая, но и символическая, знаменующая переход проекта на новую стадию разработки: более структурированную и прогнозируемую.

Итак, кратко о новых фичах.

1. Возможность обновления ASDF.
Сейчас любой пользователь может воспользоваться самой новой версией ASDF, просто загрузив ее через (asdf:oos 'asdf:load-op 'asdf) (но не через require!) Подробнее об этом в мануале, который, также улучшается.

2. Более простой пользовательский интерфейс — это функции load-system, compile-system и test-system. Вроде бы как, тривиальное изменение, но избавляющее новичков от необхоимости думать, почему это операции load-op и т.п. являются объектами, а не функциями, и других схожих волнений. Это важно в борьбе с кажущейся сложностью ASDF. При этом методы на test-op, как и раньше — и это понятно — нужно описывать разработчикам систем.

3. Системный реестр (source-registry) — новый способ конфигурации :)
Именно таким является новый, и по замыслу авторов основной способ задания места расположения исходников систем у пользователя. В то же время старый вариант через *central-registry* остается полностью функциональным и поддерживаемым. Более того, он был дополнен проверкой на самую неприятную и, наверно, частую ошибку при использовании ASDF — отсутствие слеша в конце пути к директориям — теперь этой неразберихи больше не будет.

Что же такое системный реестр? Это набор конфигурационных файлов в предопределенной структуре директорий для каждого пользователя, смоделированных по принципу *.conf.d директорий в Unix. А также собственно DSL для конфигурации. Простой пример того, как это работает из мануала:
В директории ~/.config/common-lisp/ находится файл source-registry.conf со следующей конфигурацией:

(:source-registry
(:tree "/home/fare/cl/")
:inherit-configuration)

В данном случае поиск установленных систем производится рекурсивно в поддиректориях в /home/fare/cl/.


Однако это объяснение и пример далеко не исчерпывающи, поэтому лучше читать соответствующий раздел руководства и проверить все собственноручно.

Честно говоря, как по мне, то новый подход для индивидуального разработчика менее удобен, чем использование *central-registry*. Однако он лучше подойдет для средств автоматического конфигурирования (и, я думаю, что как раз опыт в рамках ITA, где используется много Lisp серверов приложений, послужил отправной точкой для разработки этого способа), а также для использования в пакетных менеджерах. И хорошо, что теперь есть альтернативы для каждого из случаев.

4. Cохранение FASL-файлов теперь происходит в компилятор-специфичных директориях, по умолчанию спрятанных в домашней диретории пользователя. Благодаря этому устраняются проблемы как конфликта прав в случае использования одних и тех же исходников библиотек разными пользователями, так и stale FASLs, которые возникают при апгрейде реализации (в частности для SBCL).

5. В общем, исправлены основные недочеты, которые присутствовали в ASDF при работе с путями в разных операционках, а в классы компонент и система добавлены слоты, указывающие абсолютное положение их в файловой системе. Также исправлены и некоторые другие баги, о чем можно почитать в Changelog'е.

Какие проблемы остались? Из существенных для меня — две: нечеткая семантика форсированных операций (параметр :force t), а также недостатки работы с версиями (этой теме будет посвящена отдельная запись, поэтому не буду касаться ее здесь).

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

В следующей записи — немного о внутренностях ASDF...




1 Мой алгоритм установки Lisp библиотеки:
- Загрузить tar.gz файл
- Развернуть в ~/lib/lisp/
- Создать символическую ссылку на ASD-файл в ~/.lisp/
- (И вариация для случая работы с разными версиями одного пакета): ссылка на ASD-файл основной версии в ~/.lisp/, а при необходимости использования альтернативной версии, скажем hunchentoot-0.15.7 вместо hunchentoot-1.1.0 (push "~/lib/lisp/hunchentoot-0.15.7/" asdf:*central-registry*) (аналог PATH).

2010-06-29

Что такое стартап?

Или точнее, что отличает настоящий стартап от других видов бизнеса? Еще один вопрос, не имеющий никакого практического значения, но всегда являющийся интересной темой для поговорить :)

После 2-х лет, в течение которых я более-менее имею отношение к этой сфере, сегодня пришла простая формулировка, что же я под ним понимаю.

В общем, стартап — это начинание, в котором сочетаются и сбаллансированны 3 составляющих: исследовательская, инженерная и бизнес. Исследовательская отвечает за сферу инноваций, инженерная — за их "доставку" до конечного потребителя, а бизнес — за извлечение из этого денег, позволяющих продолжать работу, развиваться и достигать личных целей основателям. При этом тут, на самом деле, не важна сфера: инженерия сейчас нужна не только в Интернете :), но и в биохимии, и во флористике. (Вот, кстати, хорошая цитата про то, почему же отдельно исследование, а отдельно инженерия, случайно встреченная мною в статье в Википедии: "The theory, while correct in as far as it goes, is not sufficient to allow one to do engineering").

При этом про стартапы часто говорят, что в их основе лежит масштабирование, но, как по мне, это естественное следствие того, что все 3 компоненты присутствуют и хорошо работают: исследования обеспечивают то, что стартап реально помогает людям, т.е. на его продукты есть масштабный спрос, инженерия обеспечивает возможность удовлетворить требуемый масштаб клиентов, а бизнес — донести до них информацию о такой возможности.

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

2010-06-16

Mathematicians vs computer scientists

There is a considerable difference between a mathematician’s view of the world
and a computer-scientist’s. To a mathematician all structures are static: they have
always been and will always be; the only time dependence is that we just haven’t
discovered them all yet. The computer scientist is concerned with (and fascinated by)
the continuous creation, combination, separation and destruction of structures: time is
of the essence. In the hands of a mathematician, the Peano axioms create the integers
without reference to time, but if a computer scientist uses them to implement integer
addition, he finds they describe a very slow process, which is why he will be looking
for a more efficient approach. In this respect the computer scientist has more in com-
mon with the physicist and the chemist; like these, he cannot do without a solid basis in
several branches of applied mathematics, but, like these, he is willing (and often virtu-
ally obliged) to take on faith certain theorems handed to him by the mathematician.
Without the rigor of mathematics all science would collapse, but not all inhabitants of a
building need to know all the spars and girders that keep it upright. Factoring off cer-
tain detailed knowledge to specialists reduces the intellectual complexity of a task,
which is one of the things computer science is about.
--"Parsing Technics"

2010-05-31

Парадигмы программирования, followup

Полтора года назад написал про парадигмы программирования. Сейчас подумал, что нужно называть вещи своими именами, а не так, как принято. :)

Например, функциональный язык — это такой, где вы будете задачи решать через функции. Т.е., когда вы беретесь за новую задачу, то напишите какой-нибудь defun или function. Следующим ключевым свойством функциональных языков является вот что: все есть выражение (expression), т.е. возвращает значение, а не утверждение (statement). Всё. На этом функциональность, строго говоря заканчивается. Но есть еще очень много других видов языков. Вот Haskell, например, язык, вообще говоря, не такой уже функциональный язык. Потому что решать вы все будете через типы и напишите сначала Data :: Type. А функции — лтшь один из частных случаев этих типов (один из типов, попросту говоря), но ведь гораздо интереснее такие типы, как монады или функторы. В общем, язык, на самом деле, алгебраический, т.е. для математиков (по складу ума). Вообще, все языки более-менее для кого-то там по складу ума.

Далее, вот, Common Lisp — наполовину функциональный, наполовину декларативный (потому что в половине случаев я начну не с defun, а с defmacro). А еще на треть объектно-ориентированный, потому что для defclass тоже часто найдется место (но без фанатизма). А Scheme — действительно чисто функциональный, так кроме функций больше ничего нет. Дальше посмотрим на Erlang — это сперва язык для конкурентного программирования. Всё закручено вокруг процессов и обмена сообщениями между ними. Это только на поверхности там пролог и функции, это всего лишь синтаксис. Т.е. нельзя отрицать функциональную ориентированность Erlang'а, но язык таки process-oriented/message-passing. А что же этот знаменитый функциональный язык JavaScript? Нет, нет и нет: "всё — выражение" не выполняется, и хотя функции — обычный синтаксис для записи кода, но ядро языка — это события и коллбеки, event-driven, как говорят американцы.

Возьмем теперь Ruby. Тут всё на классах и лямбдах, т.е. анонимных функциях. А обычные функции превращены в сообщения. Да еще и всё — выражение. Вот такая анархия или мультипарадигменность. И ко всему прочему полный контроль у программиста. Получается объектно-procедурно-немного декларативно-ориентированный. Еще есть Python. Тут все немного (или намного) регулярней. Есть классы и функции, но не всё выражение, анонимных функций, считай нет. В общем, glorified C (как хорошо показывет пример Cython), но, главное, что динамический и разумно простой. Современный объектно-ориентированный процедурный язык, в общем.

C Java, например, всё понятно. Тут чистый классовый подход. Класс на inner классе сидит и анонимным классом погоняет. Говорят, это называется объектно-ориентированный подход, хотя это, вообще-то, про Smalltalk или даже про Python. А тут у нас класс-ориентированный, чистой воды. На закуску остается C++, которому можно всё, особенно в версиях Boost и 0x. Только вот, забывают заметить, что это 3 отдельных языка: С, ++, а также еще Tempaltes. И это не говоря про препроцессор. Тут тоже, как бы, всё class-based, но всё — не объект, а указатель. Короче говоря, такой машинно-ориентированный язык с системами типов и классов, в придачу к возможности застрелить себя в ступню, как говорят опять же американцы...

Про brainfuck и все остальное более-менее без изменений.

2010-05-26

Лисп — философия разработки

Написано для: Практика функционального программирования №5
Соавтор: Александр Манзюк


Чтобы не делать перепечатку, помещаю тут только аннотацию. Основной текст — по ссылке выше.

В статье исследуются подходы к разработке, практикуемые в Лисп-среде, на примерах решения различных прикладных задач на языке Common Lisp. Вы узнаете о том, что макросы — это не только синтаксический сахар, но и прекрасный инструмент инкапсуляции, что кроме глобальных и локальных переменных бывают еще специальные, что полиморфные интерфейсы можно создавать без привязки к классам, а также о том, что определять стратегии передачи управления можно не только с помощью монад. Рассмотрены и решения прикладных задач: клиент для хранилища данных Redis, прокси между двумя бизнес-приложениями, внутренний API веб-сервиса, библиотека парсерных комбинаторов.

2010-05-18

Простая модель налоговой реформы для малого И крупного бизнеса

Я не буду касаться здесь каких-то сложных с экономической точки зрения идей и тем, таких как: нужно или не нужно НДС и т.п. Взамен же попробую обратиться к столь общим вопросам, как: простота, эффективность, сбаллансированность и справедливость,— которых "немного" не хватает в текущей системе. Отсюда, как по мне, и растут ноги у всех проблем.

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

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

Далее, не так очевидно, но легко понять, что в текущем виде упрощенная система — это проблема не только для государства (уход от налогов), но и для других форм бизнеса, а также... для самих предпринимателей.

В чем проблема для других форм. Простой пример: есть человек, который выполняет какую-то профессиональную деятельность, например, моет окна. Он может делать это в рамках компании и получать зарплату 4000 грн в месяц, при этом налоговое бремя, которое ложиться на такую компанию — еще 2400 грн, а сам человек на руки получает 3400 грн (а 15% платит налога на доход). Если он моет 20 окон в месяц, то за каждое окно компания должна брать с заказчика 320 грн (+ НДС :), чтобы хотя бы выйти в 0 (будем считать, что больше расходов нет). Теперь представим, что тот же человек моет окна как частный предприниматель: теперь, чтобы получить свои 3400 грн, ему нужно выручить всего то 3600, т.е. при цене 320 грн за окно, помыть около 11 с хвостиком окон. А если он помоет 20, то заработает 7800, что ровно в 2 раза больше. Спрашивается, как компания сможет конкурировать с таким фрилансером? Отсюда и зарплаты в конвертах, и "оптимизация" через СПД. Т.е. виновато не только высокое налоговое бремя (хотя это виновник №1), но и несбаллансированная налоговая система (хотя это все-таки только №2).

Второй момент: допустим человек моет окна самостоятельно, но не регистрируется как СПД, а платит обычный налог на доход (15%). Хотя такая ситуация немного противоречит закону, однако, по сути, это те условия, в которых находятся все наемные работники, если вообще не принимать в рассмотрение компании. Т.е. наемные работники тоже проигрывают СПДшникам на эти 15%.

Теперь рассмотрим вопрос пенсий. СПД-шник платит в пенсионный фонд 84 грн. В то же время любой наемный работник платит 33,2% своей зарплаты, что составляет минимум 300 грн. В результате оба будут получать одинаковую социальную пенсию. Но даже, если человек будет иметь сногсшибательную зарплату и платить огромные отчисления в ПФ, никто не гарантирует, что через 30 лет он будет получать какую-то громадную пенсию, как и сейчас не получают большой пенсии советские герои труда, проработавшие по 50 лет на каких-то вредных производствах и т.д. Потому что государство у нас такое, ответсвенное. Зато из этих отчислений будет платиться огромная пенсия сегодня депутатам, секретным агентам и академикам. Это, ясное дело, абсолютно не справедливо и неэффективно. Как эффективнее — ниже.

Итак, существование СПД-формы — это громадная несправедливость по отношению к: 1. компаниям, 2. простым работникам 3. будущим пенсионерам.
С другой стороны, проблема не столько в ней, сколько в гигантском налоговом бремени на компании, точнее собственников (почти 60% начисления на зарплату наемных рабочих + 25% налог на дивиденды, который, фактически, является двойным налогообложением). Это бремя приводит к тому, что блокируется рост зарплат и происходит тенезация экономики. А в пенсионном фонде все равно дырка, которая покрывается из бюджета.


Предложения по решению проблемы исходят из простейших идей:
1. СПД — это самозанятый профессионал, который делает работу самостоятельно.
2. Пенсии должны быть справедливыми (во всех отношениях :)

Соответственно:

1. СПД форма должна существовать и еще более упроститься.
- Во-первых, в области видов деятельности. Зачем искусственно ограничивать людей: есть специалисты широкого профиля, почему не дать им заниматься теми разными занятиями, которые им по душе? Т.е. КВЕД можно оставить только для статистики, но ни в коем случае не делать его ограничением, как сейчас.
- Во-вторых, уплата налога должна быть не такой частой (хотя бы раз в квартал), особенно в связи с п.2
- В-третьих, нужно убрать верхнее ограничение на размер выручки (если специалист мирового класса зарабатывает миллионы, он что, перестает быть предпринимателем?), но в то же время СПД не должен использовать наемный труд. Вообще. Если нужны помощники, пускай тоже оформляются как СПД и работают по подрядному принципу. Если у вас есть сотрудники, то это уже компания. Просто, у нас создание компании является нереально сложным делом.

2. Ставка налога на СПД должна быть приравнена к налогу на доход физлиц. Это, во-первых, справедливо по отношению к наемным работникам, во-вторых, выгодно для государства. Ну и, в-третьих, не вызовет принципиальных возражений у любого предпринимателя, который понимает, что налоги платить надо, но они должны быть подъемными. В то же время это будет справедливо к тем, кто по каким-то причинам не работает на данный момент как предприниматель: нет прибыли — нет налога. Вообще, предприниматель, который временно (от 1 квартала) сидит без работы, также должен иметь право стать на биржу труда, как и обычный уволенный сотрудник и какое-то время получать социальное пособие. О соцопсобии — ниже.

3. Сферу соцфондов можно радикально упростить и, при этом, сохранить существующие пенсии (потерять которые так боятся чиновники). Все трубят о втором уровне пенсионной системы, но никто не пытается доходчиво объяснить, что это такое. На самом деле все должно выглядеть очень просто: должна быть единая, не зависящая от зарплаты, социальная пенсия, которая выплачивается всем нетрудоспособным людям из ПФ, а также социальная помощь по безработице от государственной страховой компании. Обе эти величины должны равняться прожиточному минимуму. Помощь от несчастных случаев тоже должна быть стандартизована и зависить только от категории (тяжести) травмы, а не от зарплаты. Таким образом, имея статистику по количеству работающих, пенсионеров, безработных и несчастных случаев, можно рассчитать необходимую величину единого социального взноса с каждого работающего (не зависимо от того, сотрудника компании, или СПД, или даже рантье) на бюджетный год для выхода на нужные цифры компенсаций для неработающих. (Т.е. для СПД помимо налога на доход добавляется единый социальный взнос, меняющийся из года в год. Такой взнос нужно будет платить раз в месяц или же наперед).

А как быть с пенсией, которая выше социальной и т.п.? Для этого и существует второй уровень пенсионной системы, как и второй уровень страховой системы. Он состоит из добровольных отчислений работающих сверх обязательного социального взноса. Естественно, такие добровольные отчисления могут делаться как в государственный ПФ и СК, так и в негосударственные по выбору страхователя. И они должны быть персонализированны. Впрочем, такие отчисления могут делать за сотрудников и компании (опять же добровольно), и иметь в связи с этим какие-то налоговые льготы и т.п. (это уже вопрос экономических моделей). Также, например, государство может делать такие отчисления для всего госаппарата, чтобы сохранять существующую сейчас систему высоких пенсий чиновникам — это будет его конкурентным преимуществом на рынке труда :)

А как покрывать дефицит ПФ для выплаты текущих обязательств государства сверх социальной пенсии (средства на которую, напомню, собираются через единый социальный взнос): пенсий, которые уже начисленны пенсионерам, которые, разумеется, не могут делать никаких отчислений? На самом деле, также как и сейчас — из госбюджета и это будут очень большие деньги :) Но хорошая новость в том, что с введением такой пенсионной системы обязательства бюджета будут с каждым годом уменьшаться, как и список тех пенсионеров, которые будут получать пенсию старого образца. Остается вопрос, как быть с теми, кому 54, 58, 50? Для них (как и для всех остальных работающих) можно ввести прогрессивную шкалу пенсии, которую уже должно государство: разделить количество роработанных лет на полный стаж до пенсии и получить процент от той пенсии, на которую человек мог рассчитывать по старой системе. Т.е. для человека, которому остался работать год, а он проработал 24, это будет 96%, а для того, кто проработал 2, а еще впереди 32 это будет 4%. Это обязательство государства, как и перед текущими пенсионерами. Остальную сумму можно будет набирать за счет добровольных взносов.

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

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

2010-03-28

GUI в Common Lisp — еще один миф

Написано для: habrahabr.ru

Бытует расхожее мнение, что в Common Lisp нет или же плохая поддержка графики. Это еще один миф из серии, что Lisp — это язык только для подсчета факториалов. На самом деле, как и в большинстве других прикладных сфер общего назначения (например, веб, форматы передачи данных, взаимодействие с БД и т.д.) в Lisp-среде есть полный спектр библиотек и тулкитов для всех основных платформ с разными уровнями абстракции.

Linux/Unix


Базовой библиотекой для графики из Common Lisp под Unix является CLX. Это аналог xlib, т.е. низкоуровневый клиент, напрямую общающийся по X-протоколу.

Кроме того, есть обертки для основных графических фреймворков разной степени зрелости: LTK, CL-GTK2, CommonQt, CL-CAIRO2. Лично мне доводилось иметь дело с LTK, и работа с ним тривиальна. Хороший пример приложения, его использующего — простой и удобный Lisp-редактор/REPL ABLE.
ABLE screenshot

Windows


Кроме возможности использовать кросс-платформенные фреймворки из прошлого раздела, есть еще LispWorks CAPI, о котором только положительные отзывы. Единственная особенность заключается в том, что, как и большинство профессиональных сред разработки на любых языках под Windows, LispWorks стоит довольно дорого (ок. 1200 $), а CAPI доступна только в профессиональной версии. (Впрочем, попробовать его можно и в trial версии).

Также есть CL-OPENGL, которая, разумеется, кросс-платформенная.

MacOS X


Дополнительно к Unix-библиотекам для MacOS X есть хорошие Cocoa-биндинги в Clozure CL.

Специфические Lisp-решения


Библиотека McCLIM реализует Lisp Interface Manager спецификацию, определяющую весьма развитый протокол по оперированию с графическими примитивами. Хотя спецификация является платформо-независимой, сама библиотека на данный момент основанна на CLX с вытекающими отсюда последствиями пригодности только для Unix-среды. Если это не есть ограничением, то именно она нужна вам, если вы собираетесь писать что-то, сильно завязанное на графику: игру, графический или CAD-редактор, или же новый EmacsClimacs.
Climacs

Оригинальным подходом к GUI, зародившимся в Lisp-среде является проект Cells, который переносит spreadsheet-парадигму взаимозависимых "ячеек" на графический интерфейс. У него несколько Lisp-реализаций c тем или иным бэкендом: CELLS-GTK, CELLTK, CELLO,— а также есть и порты на другие языки.

Выводы


В общем, варианты есть на любой вкус и запросы. С чего начать? Для простого GUI я бы выбрал LTK или CL-GTK2. Оба они кросс-платформенные. Первый по причине максимальной простоты, даже примитивности. Соответственно, и подходит он для примитивных приложений. Второй — потому что это хорошая обертка для современной объектно-ориентированной графической библиотеки, активно развивающаяся, да еще и с русским автором :)

PS. Еще несколько более специфических графических библиотек, конечно, можно найти на Cliki.

2010-03-27

Пару мыслей об SCTest

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

В этот раз панель была очень показательна, поскольку на ней присутствовали представители 3-х основных категорий участников test'а:
- состоявшийся, как правило, без сторонней помощи (венчурных инвесторов), а благодаря личным качествам и работе, предприниматель. Как раз пример того, у кого есть чему поучиться;
- tru стартапер, т.е. человек, хорошо изучивший стартап-"технологии", как правильно надувать пузырики, что нужно говорить инвесторам и т.п. (Эти качества, по моему мнению, на самом деле независимы от настоящих бизнес-качеств, которые присущи первой категории людей, так что "настоящий стартапер" может как ими обладать, так и не обладать);
- startup kiddie (по аналогии со script kiddie), т.е. молодой человек, увлеченный хайпом стартап-движения, и порой считающий, что сможет в этой игре переиграть "старших товарищей" (упреждиск: если относить меня к какой-то из этих категорий, то разве что к этой).

Интересна реакция на выступление представителя M$ — как раз синдром startup-kiddies, которые всё знают и всё могут. Я не говорю о том, что у большинства из пристуствующих на компьютере стоит ворованная копия той самой Windows (упреждиск: пишу это на Linux). Дело в другом: выступал отличный профессионал, с местами интересным докладом, содержащим много полезной информации (конечно, не без корпоративщины и прямой рекламы, а также самолюбования: оказывается, Vista была провалом, потому что Intel с чипсетами подкачал :) А реакция была не поискать интересное, а поерничать, когда же он будет кричать "Developers, developers...", и поприкалываться, что человек не умеет пользоваться PowerPoint'ом (что в данном случае было банальной глупостью). Элементарной культуры и самоуважения не хватает...

2010-03-15

What's on Coders' Minds?

Recently I've finished reading Coders at Work by Peter Siebel — another excelent book, that has given me a lot of food for though concerning programming. This weekend I've decided to perform a little analytics on it to see common patterns. I've collected statistics on the questions of programming language use, interrelations between them and topics, that might be relevant for the sequeals (there are so many other great programmers out there in the wild :)

1. Programming language preferences

First comes C, that was mentioned by all the coders. Only Peter Norvig didn't speak about it in some detail. It seems, that everyone had at least medium experience programming in it (except maybe for Norvig and Fran Allen), which proves, that the language truly is the Lingua Franca of programming community.

Next in terms of mentions comes C++, Java and Lisp, that were mentioned by more than 12 people.

C++ netted mostly negative or at least neutral reviews. Moreover, it seems, that only a couple of people had any big real-world coding experience in it: others (like Jamie Zawinski) tried to avoid using it at all cost.

On the contrary at least 4 of the people had a substantial hands-on involvement in Lisp programming, but mostly in the past decades. Others mentioned it more as an important alternative or a design influence.

The same amount of coders were really experienced in the Java world. Others just mentioned it as either the recent derivative of the Algol-family, or as a typical example of object-oriented approach, or for its automatic memory-management capability.

Next comes a pack of languages, that are mostly in wide use today, some gradually falling from grace and some getting more traction. These include: Fortran, Assembler, Python, JavaScript, BASIC, Perl and Pascal. All were mentioned by 6 to 10 people. Among them Assembler, BASIC and Pascal are obviously mostly out of use, but were the three most mentioned first languages in someone's carrers. And Fortran has it's distinct role as the default scientific language (and as the first high-level language).

The next group of languages were mentioned rarely, but they were supported by strong advocates. These are Haskell, Smalltalk, and to a lesser extent Scheme and the ML family. Also the same amount of mentions went to the now defunct previously important ones: Tcl, APL, PL/I, BCPL, and COBOL.

Interestingly enough some of the most wide-spread languages of today: PHP, C#, and Ruby,— were mentioned only once or twice and only in passing. The same concerns 3 other more or less important contemporary languages: Objective-C, Scala and Erlang,— that got only a single mention. The reasons for that seem to be different, but one of them can be, that bright representatives of those languages' communities (except for Erlang's creator Armstrong) were not interviewed.

Finally, a host of other languages, not in use today, got mentioned at least twice. They are: Ada, Algol, Eiffel, E, Prolog, Self, Simula, SNOBOL and Teco.

2. Social graph

Coders social graph

4 of the coders had some Berkley background, 3 — MIT and 2 — CMU. Among the most important organizations were Google (4 coders work there and 4 other mentioned its practices), Microsoft (1 employee and 7 other having some problem with them), IBM (1 employee, mostly everyone's first computer :), Xerox PARC and Netscape/Mozilla.

Also worth mentioning is that 13 of 15 interviewed programmers were from the USA, 2 from Europe.

3. Recommended books

* SICP (5 mentions)
* The Art of Computer programming (obviously) (5 mentions)
* Design Patterns (3), although all spoke of it as at least controversial
* The psychological books: "The Mythical Man-Month" and "Psychology of Computer Programming", each brought up both by Steele and Bloch (2 mentions)

And once were recommended these books:
* Beautiful Code: Leading Programmers Explain How They Think, Andy Oram, Greg Wilson (eds.) (O’Reilly, 2007)
* Code Complete, Steve McConnell (Microsoft Press, 1993)
* Compiling with Continuations, Andrew W. Appel (Cambridge University Press, 1992)
* The Design and Analysis of Computer Algorithms, Alfred V. Aho, John E. Hopcroft, and Jeffrey D. Ullman (Addison-Wesley, 1974)
* The Elements of Programming Style, Brian Kernighan and P.J. Plauger (Computing McGraw-Hill, 1978)
* Elements of Style, William Strunk and E.B. White (Longman, 1999)
* Hacker’s Delight, Hank Warren (Addison-Wesley, 2002)
* Higher-Order Perl, Mark Jason Dominus (Morgan Kaufmann, 2005)
* Java Concurrency in Practice, Brian Goetz, Tim Peierls, Joshua Bloch, Joseph Bowbeer, David Holmes, and Doug Lea (Addison-Wesley, 2006)
* Java Puzzlers: Traps, Pitfalls, and Corner Cases, Joshua Bloch and Neil Gafter (Addison-Wesley, 2005)
* Programming Pearls, Jon Bentley (ACM Press, 1999)
* Purely Functional Data Structures, Chris Okasaki (Cambridge University Press, 2008)
* Zen and the Art of Motorcycle Maintenance: An Inquiry into Values, Robert Pirsig (Bantam, 1984)

The only unexpected omission seem to be "Goedel, Escher, Bach: an Eternal Golden Braid", which is the favorite programming book of many.

4. Other things

The tools in use include Emacs (most mentioned) and GDB. Others were: Java IDEs (Eclipse, NetBeans and IntelliJ), profilers, and correctness checkers, like JSLint, Valgrind and QuickCheck.

There were also a few topics, brought up by many of the coders, apart from the ones, explicitly triggered by the interview questions. Those are API and GUI design (often in connection with the ugliness of WinAPI), transactional memory (and other ways of tackling the massively multicore world), and means of inter-process communication and data-interchange. This may be a suggestion for questions of the future interviews.

Some of the coders came to programming through games or programmed some. 2 times were mentioned Pac-Man and the Game of Life. Also variants of tic-tac-toe, tetris, and Adventure were named. Still game programming is one of the most important parts of the programming industry and no prominent person from it was present (although John Carmack was planned).

5. Conclusions (who to interview next?)

The next candidates can be derived from the mentions' graph, but this can lead to confinement inside of the subset of all programming communities due to the cluster nature of "schools" of influence. So it's also worth considering the missing languages and georgaphical diversity.

So, among the important pears of our coders were:
* Richard Stallman, founder of the FSF and GNU (3 mentions)
* Guido van Rossum, creator of Python (3)
* Bjarne Stroustrup, creator of C++ (3)
* Danny Bobrow, a prominent lisper (3)
* Larry Wall, creator of Perl (2)
* Adele Goldberg, who was at the root of object-oriented movement (2)
* Bill Gosper, another prominent lisper (2)

Also were mentioned the famous computer scientists: Edsger Dijkstra, Tony Hoare and Noahm Chomsky.

It can be seen, that the mentioned persons were mostly programming language designers. But this book showed, that it is equally important to present the opinion of language users, because in many areas it can diverge. In search of such people we can direct ourselves to the "missing languages" side. And the first one of those is actually C++ for its wide spread is not reflected by the interviewed, who were important representatives of that school of thought. Apart from language's creator Stroustrup, 2 people come to mind: John Carmack of idSoftware fame and Raymond Chen from Microsoft. The Ruby camp has another interesting feature: it's main proponents are very loudly heard in the programming world. David Hanson, Dave Thomas, Reginald Braithwhite, Tim Bray and Chris Wanstrath (Github) all have influential blogs. The other one famous Ruby programmer, whom it could be really interesting to interview, is Why the Poignant Stiff. It would also be interesting to hear the voice of those "unknown" heroes of the PHP and C# world, because it can resonate with lots and lots of programmers in the world. From other (well represented in the previous book) communities the prominent figures are Ian Bicking (Python), Edi Weitz (Lisp), Ward Cunningham (Java) and Luke Gorrie (Erlang, Smalltalk, Lisp).

This book also featured a number of interviews with computer scientists: Knuth and Allen, as well as Norvig, Steele and Peyton Jones (although those three are more on the practical side). Among their pears in the CS world, obviously, the most mentioned were Abelson and Sussman. Next come Danny Bobrow, Aho and Ulman (among the living).

Talking about geographical diversity, Edi Weitz and Luke Gorrie represent Europe. Other interesting European coders are the creators of PHP Rasmus Lerdorf, Prolog Alain Colmerauer and OCaml Xavier Leroy. And in every programming community there can easily be named prominent European hackers (like Ola Bini from JRuby team). It is also worth "visiting" Japan, the former USSR (that had it's own tradition in CS and software), and, possibly, India and China. From Russia such people as: Eugene Roshal (creator of the Rar compression format), Stepan Pachikov (founder of Evernote), and Viktor Shchepin (author of ejabberd Erlang-based jabber server),— can be named.

Finally, the last diversity question, that was raised by Peter Siebel himself, is women participation. The first woman candidate, that can be derived from the analysis, is Adele Goldberg. One other woman, that comes to mind, is Allison Randal, working on the Parrot virtual machine and Perl 6 programming language.

(Actually most of the mentioned names were in the list of possibil candidates for the first book).

2009-11-07

О страшных монадах

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

Как верно было подмечено, монады — это очень просто. А еще монады — везде. Почему же тогда у многих с ними проблемы?

1. Терминология
Где-то написано, что использование нетипичной для предметной области терминологии — это аттрибут троллинга (к сожалению, не удалось найти ссылку). Можно возразить: "да ведь монады — это же математический термин". Да, но математика и инженерия (в частности, программирование) — разные дисциплины. Математики не строят мосты, да. А термин монада не относится к предметной области программирования. В ней есть такое понятие как "вычисление" (computation). (Пусть меня осудят, но) фактически, монада в Haskell — это стратегия вычисления.

Почему же тогда говорят "поместить/извлечь значение в/из монаду/ы"? Говорят так для простоты. На самом деле, можно лишь запустить определенное вычисление с определенным входным значением (отсюда и идиома run...). Слишком похоже на "запустить процедуру", не так ли?

Так что с термином "монада" либо создатели Haskell были недостаточно дальновидны, либо, просто, хотели эпатировать программистский мир.

2. Подход к изучению
К сожалению, большинство объяснений монад так или иначе отталкиваются от того, что монада — это всего навсего тип и 2 простые функции. Но проблема в том, что от того, что вы поймете, как работают функции return и bind, вам не станет сразу ясно, зачем они нужны вместе. Отталкиваться в понимании того, что такое монады стратегии вычисления, нужно от того, зачем они нужны? Сейчас я сделал именно так, и все легко стало на свои места.

Какие бывают стратегии вычисления? Я сейчас не буду называть самую важную из них, а напишу о ней в следующей записи — пока предлагаю прийти к ответу самостоятельно. Могут быть: вычисление, которое завершается неудачно, если неудачно завершается хотя бы одно из внутренних подвычислений — это знаменитая монада Maybe, которую мы сейчас рассмотрим. Может быть вычисление, которое использует какое-то доступное для всех подвычислений "хранилище" данных — State. Есть вычисление, которое связанно с обменом данными с внешней средой — IO и т.д.

Бытует мнение, что Haskell — ленивый язык (более того, это официальная позиция). На самом деле, все немного сложнее или проще, зависит от того, как посмотреть. Во-первых, всем понятно, что абсолютно (или, как говорится, чисто) ленивого языка быть не может, поскольку в таком случае мы никогда не получим какого-то результата работы программы. Каким образом Haskell'исты выходят из этого затруднения? Принято говорить, что, в целом, язык ленивый, а вся неленивость/энергичность (eagerness) находится (так и хочется сказать, заточЕна) внутри монад. Но дело в том, что любая Haskell-программа находится внутри монады IO. В итоге оказывается, что ленивыми в Haskell являются только чистые функции, а все вычисления (в понимании программистском), которых, на самом деле, большая часть — все равно остаются энергичными. В то же время любая чистая Haskell-функция, учитывая pattern matching и немутируемые переменные, по большому счету представляют из себя одну case-конструкцию и вызов других функций. Красиво? Часто, да. Однобоко? Тоже. ОК, но самое интересное дальше.

И в других языках примерно то же самое! По сути, разница только в том, что:
(а) не проведена четкая граница между ленивыми вычислениями и энергичными. Впрочем, каждый может для себя ее проводить сам: например, можно думать о ленивых вычислениях как об аттрибутах "математических" функций (и таким образом их и программировать), а об энергичных — как о процедурах. В любом языке может быть реализована ленивая стратегия вычислений, однако не везде это сделать одинаково легко...
(б) программист самостоятельно может строить процесс вычисления адекватный конкретной задаче. По сути, построение вычислительных процессов и есть одно из главных составляющих собственно того, что мы понимаем под программированием
Можно выдвинуть предположение, что все разные виды вычислений можно свести к нескольким десяткам определенному количеству монад. И, изучив их, можно будет составлять вычисления, как кубики в конструкторе. (И это предположение действительно выдвигается). В таком случае монады и вправду становились бы решающим методом абстракции в программировании. Впрочем, оказывается, что даже сведя вычисления к монадам, составлять их также легко, как кубики, не удается, и приходится прибегнуть к помощи еще одних монад — монадных преобразователей (monad transformers). В итоге, монада на монаде сидит и монадой погоняет... :) (Можно было догадаться исходя из принципа вычислительной эквивалентности. Вообще говоря, приняв во внимание этот принцип, можно понять, что максима "there is no silver bullet" таки справедлива всегда).
И еще одно: вывод про сведение всех вычислений к определенному набору не нов. Он лежит в основе структурного программирования, где доказано, что все вычисления можно свести к комбинации последовательного выполнения, условного выражения и цикла.

Вот тут то разница между Haskell'ем и другими языками становится наиболее существенной: другие языки имеют синтаксическую поддержку определенного узкого набора монад, и дают возможность создавать другие монады ad hoc с использованием того или иного механизма. Haskell, по сути, делает то же самое, только создание новых монад регуляризирует и вгоняет в определенные рамки. Итак Haskell — это язык, в котором дисциплина на первом месте.

В общем, концепция монад очень полезна, чтобы понять, что могут быть совершенно любые стратегии вычислений и не стоит считать, что возможны только те, которые определенный язык считает родными (вот, в С не было стратегии вычисления Exception, а в С++ появилась :)

Возвращаясь к Maybe. Его все понимают, так ведь? Это нужно для того, чтобы если где-то в последовательности вычислений у нас получился элемент Null (Nothing), это значение в итоге вернулось в качестве результата, и при этом другие части вычисления не имели проблем с обработкой такого значения.

Этот шаблон хорошо знаком всем, кому доводилось встречаться с логическими операторами с коротким замыканием. Идеально он работает в Common Lisp, где значение nil также является логической ложью (это, кстати, считается многими одним из кардинальных преимуществ Common Lisp над Scheme, в котором эти 2 значения разделены). Ниже приводится пример реализации Maybe на CL, аналогичный примеру из пособия по монадам:

(defmacro maybecall (val &rest funs)
"Consequently apply a sequence of FUNctionS to the
return value of the previous computation, starting with VAL"
`(and-it ,val
,@(mapcar (lambda (fun)
`(funcall ,fun it))
funs)))

;; где:
(defmacro and-it (&rest args)
"Like AND, but IT is bound to the value of the previous computation"
(cond ((null args) t)
((null (tail args)) (first args))
(t `(let ((it ,(first args)))
(when it
(and-it ,@(tail args)))))))

;; работает?

(defun mother (x)
(gethash x *mothers*))

(defun father (x)
(gethash x *fathers*))

(setf (gethash :b *fathers*) :e
(gethash :a *fathers*) :d
(gethash :b *mothers*) :c
(gethash :a *mothers*) :b)

(maybecall :a #'mother #'father) => :e
(maybecall :a #'mother #'father #'father #'brother) => nil
;; и даже на brother не ругается, потому что до него дело не доходит


Впрочем, я понял, что обычный AND (или AND-IT) в CL — это и есть полноценная реализация Maybe стратегии. Притом простая и понятная, нет?

3. Нужны ли монады за пределами Haskell'я?
То, что в других языках представляет из себя единую ткань вычислений, в рамках Haskell разделено на 2 класса: чистые (обычные функции) и "грязные" (монады). Это приводит к разделению (дублированию) синтаксиса и усложнению программного кода (полная противоположность дуалистического подхода). В то же время, это делает рассуждения о программах более структурированными и помогает (однако не гарантирует!) соблюдению принципа ссылочной целостности. В теории концепция монад полезна для понимания того, что такое вычисления. На практике же введение дополнительных правил приводит к тому, что появляется определенный предел выразительности языка и близости его к предметной области. Именно так, несмотря на заявления программистов на Haskell об обратном: концепция монады, монадного трансформера и т.д. неимоверно далеки от любой предметной области, которая встречается при программировании, а абстрагировать их средствами Haskell не удастся. Более того, само понятие вычисления, которое в других языках остается имплицитным, в Haskell'е достается на поверхность. Именно с этим, по-моему, связанны частые претензии к преувеличенной сложности Haskell программ.

---

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

Еще по теме:
* All About Monads
* Why monads have not taken the Common Lisp world by storm