Haskell в реальной жизни
Итак! Этот долгожданный момент всё-таки наступил! Я получил свой первый опыт Haskell в коммерческом программировании!
Рассказываю как дело было:
У Одной Большой Американской Корпорации есть туча проектов написанный на C#/.NET Framework 1.1 в MS Visual Studio 2003, которые плавно перекочевали на 2005 студию и FW 2.0. Всё бы ничего, да вот в C# 2.0 появилось удобная фича – классы теперь могут быть разбиты на несколько физических файлов, соответственно весь код относящийся к рисованию GUI (сгенерированный самой студией) можно отделить от кода как-то этим GUI управляющим (написанный ручками). Никаких стандартных путей выполнить такое разделение для уже написанных классов мы не нашли и было принято решение написать Утилиту. Как самый большой любитель делать что-нибудь эдакое, писать Утилиту вызвался я.
Сразу скажу, писать это на Haskell было рисковано с моей стороны, всё-таки предстояло использовать малознакомые инструменты в работе, которую надо было выполнить максимально быстро, и я всё делал на свой страх и риск. Так что в начале у меня немного подрагивали коленки :)
Чтож, первый опыт боевого использования Haskell не только удался, но и принес массу положительных впечатлений! Некоторые мысли и факты об этом опыте:
- Проектирование никто не отменял, вот только проектирование это функциональное, т.к. язык чистый, нет никаких шансов использовать наработанный на императивных языках опыт проектирования: классов нет, переменных нет, ввод-вывод через монады. Эта программка конечно малюсенькая, но у меня уже чешутся руки начать на Haskell какой-нибудь Грандиозный Проект и посмотреть насколько удобно, прозрачно и просто будет выглядеть его дизайн (или не будет).
- Для этой задачи был нужен простенький парсер, мне сразу было понятно что средствами регэкспов тут не справиться – слишком много будет частных случаев, а главное было в процессе работы исходные файлы не испортить. Сел писать парсер. Ясен пень что на Parsec'е. Ситуация слегка осложнялась тем, что это был первый парсер в моей жизни :) (первый работающий и что-то делающий, теоретические знания у меня кое-какие конечно были). На изучение Parsec'а (с уровня «несколько раз смотрел по диагонали») и написание парсера ушло 3 дня, при этом мне даже представить страшно сколько бы это заняло на менее мощных инструментах – грамматика у меня полна неоднозначностей, весь код парсера покрыт блоками try, соответственно код получился тормозным, но обладающим неоспоримым преимуществом – он работал :) . Parsec не очень порадовал своей документацией и некоторой ограниченностью в документированных способах получения его внутренних состояний. Как получить текущую позицию в виде смещения от начала буфера я так и не нашел, пришлось извращаться с получением номера строки и столбца, а потом уже с этим работать.
- Pattern-matching рулит, Pattern-matching рулит, Pattern-matching рулит! :)
- Про ленивые вычисления и монаду Maybe см Pattern-matching :)
- Ещё к вопросу о дизайне: программа представляет из себя эдакий бутерброд из map-ов, filter-ов и fold-ов, очень полезно предусмотреть способы залезть куда-нибудь внутрь этого бутерброда, иначе страшно делается :)
- Родилась мысль так описать функциональное программирование для людей знакомых с SQL (а их очень много): мы выполняем запрос, но не по таблицам, а по любым данным произвольной структуры.
- Очень здорово исправлять ошибки и вносить непредусмотренные вначале вещи: глючный блок выкинули, поставили пофикшенный, что-нибудь новенькое в середину воткнули и никаких проблем. Отсутствие побочных эффектов в этих случаях рулит неимоверно.
- Для работы с XML я использовал HXT. Библиотека могучая и вызывающая уважение самим временем её компиляции :) . Правильный путь работы с XML на HXT – это стрелки, я решил что изучение стрелок может затянуться на неопределенный срок, а копать мне надо быстро, и использовал из HXT только xread/xshow, а дальше как настоящий самурай ручками разбирал и изменял полученное дерево, этот код получился самым чудовищным.
- Сухие факты: на всё про всё ушло 7 рабочих дней. Объем исходников: парсер – 3 Кб, логика разрезания классов на GUI и на всё остальное – 8 Кб, работа с XML, ввод-вывод, обработка командной строки – 3 Кб.
Одна Большая Американская Корпорация получила выполненную работу и Утилиту, я получил кучу фана, надеюсь что и все кто до этого места дочитал извлекли для себя какую-то пользу :)