13 июл. 2009 г.

id3project is alive!

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

но о чём это я?.. об id3project!
за эту неделю я многое сделал. хотя вспомню я сейчас не всё и не в хронологическом порядке.
помимо изменений в самой библиотеке, о которых речь пойдёт дальше, я начал использовать darcs - хаскеллевскую систему контроля версий. то есть он у меня и раньше был. но теперь я попробовал подружиться с ним и действительно понять зачем мне это надо и как что-нибудь с его помощью сделать. удобно, наверное..
а ещё я нашёл бесплатных хостинг для проектов использующих darcs на patch-tag.com
не знаю что в нём ещё хорошего, кроме того, что он бесплатный и для darcs.. но мне-то и этого хватит сполна.
итак, дело приняло серьёзный оборот! думаю, скоро можно будет уже выкладывать библиотеку в hackage.

теперь, о самой библиотеке:
- были сделаны значительные усовершенствования в структурах данных, хранящих информацию тега. не упоминая конкретики самой структуры, сложно рассказать о каких-то изменениях в общем. упомяну лишь, что я стал использовать (впрочем давно) такую штуку как аксессоры из пакета data-accessor (не знаю как это можно разумно перевести). все структуры данных, которые я использую - записи (records). у записей есть поля содержащие информацию. так вот стандартный интерфейс доступа к этим полям в хаскелле довольно неудобный (имхо). аксессоры предлагают (1) более удобный интерфейс, (2) абстракцию, которая позволяет менять эти методы доступа к полям записи. так что когда я менял структуры, мне не приходилось исправлять код везде, где они используются - я просто менял аксессоры.
- функция чтения тега из файла стала лучше, проще, надёжнее.
- функция записи тега в файл была наконец таки сделана! и если я чего-нибудь не упустил,, работает она не только правильно, но и эффективно. в чём была сложность: тег хранится вначале музыкального файла. у тега есть паддинг - резервное место для дописывания (кусок файла забитый нулями). это нужно для того, чтобы если тег увеличится, не переписывать весь файл заново (у меня например встречаются mp3 по 30-40 мегабайт), а записать его поверх старого, уменьшив тем самым паддинг (пэддинг). я разобрался как это сделать аккуратно и вроде бы у меня получилось.
- и наконец, самое(?) главное! я сделал "простой интерфейс" для этой библиотеки. простой интерфейс в кавычках, потому что это - во-первых (мягко говоря) урезанная функциональность, во-вторых это называется интерфейсом в смысле программирования, а не пользования. то есть интерфейс для тех, кто программирует на хаскелле. он действительно простой. но если это то, ради чего я делал всё что я делал (а это разумеется не так),, то я был настоящим извращенцем - это как строить большой, очень надёжный самолёт, с хорошими аэродинамическими характеристиками, в котором для пилота предусмотрена удобная приборная панель с бесчётным числом рычажков, кнопочек, тумблеров и прочих элементов управления,, а потом сделать для него пульт дистанционного управления (это ведь удобно) с двумя кнопками (всё просто): "/ехать/ вперёд" и "/ехать/ назад" (ничего лишнего).
вот примерно также и с этим моим простым интерфейсом..
там есть несколько функций такого вида:
getArtist :: Tag → Maybe String
она берёт тэг и возвращает либо Nothing - ежели информации об исполнителе в тэге не имеется, либо (Just "имярек") - ежели исполнитель имярек.

setArtist :: String → Tag → Tag
эта функция берёт имя которое вы хотите записать, тэг и возвращает изменённый тэг. при этом если информация об исполнителе в тэге имелась - она будет изменена,, а если е\ не было - будет создана.

в модуле ещё несколько точно таких же функций для названия трека, номера трека, года записи и названия альбома - в ближайшее время добавлю ещё парочку (комментарий, жанр и т.п.). всё очень просто - даже не надо знать что такое Tag. кстати, откуда он тогда берётся? из файла очевидно,, с помощью функции readTag:
readTag :: FilePath → IO (Maybe Tag)
она берёт имя файла, а возвращает "может быть тэг". это значит, что если в данном файле есть id3-тэг - значение будет иметь вид (Just tag),, а если нет - Nothing.

ну и для полноты картины надо упомянуть обратную функцию - для записи тега в файл:
writeTag :: FilePath -> Tag -> IO ()
куда писать и что писать - всё просто.

итак,, стоит написать маленький пример, чтобы показать как это всё работает и о чём вообще речь.
суть нижеследующего листинга в следующем: мы прочитаем тэг, посмотрим, есть ли в нём информация о номере трека, и если есть, отредактируем - если это цифра, то поставим перед ней ноль. по-моему вполне разумное изменение - некоторые плееры некорректно сортируют треки по номерам, если не проставлены нули слева:
1, 10, 11, 2, 3 .. - это происходит потому, что номер трека хранится в теге ввиде строки, а не числа и в данном случае эти строки сортируются в лексикографическом порядке - по алфавиту.
а мы сделаем так: 01, 02, 03 .. 10, 11.


 1 import System       (getArgs)
 2 import ID3.Simple
 3
 4 main = do
 5     files ← getArgs                         -- аргументы программы - список файлов, для редактирования
 6     mapM_ (withTag correctTrack) files      -- применим к каждому преобразование
 7
 8 -- в этой функции мы изолируем ввод-ввывод    (надо бы мне добавить её в библиотеку)
 9 withTag :: (Tag → Tag) → FilePath → IO ()
10 withTag function file = do
11     smth ← readTag file                            -- читаем "может быть тэг" из файла
12     case smth of
13          Nothing  → return ()                      -- если тэга в файле нет, то не делаем ничего
14          Just tag → writeTag file (function tag)   -- если тэг есть, преобразуем его и запишем обратно в файл
15
16 -- теперь, собственно, само преобразование
17 correctTrack :: Tag → Tag
18 correctTrack tag =
19     case getTrack tag of                 -- смотрим номер трека в тэге
20          Nothing  → tag                  -- если его там нет, то возвращаем тэг без изменений
21          Just num → if length num ≡ 1    -- а если есть - смотрим цифра ли это (один символ в строке)
22                        then setTrack ('0':num) tag     -- если да - добавляем слева ноль и пишем в тэг
23                        else tag                        -- если нет - ничего не меняем

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

стоит ещё сказать о том, как проверить, что вообще что-то произошло - как посмотреть сам тэг. очень просто: print tag.
поскольку я сделал все структуры данных используемые в библиотеке членами класса Show, можно просто выводить структуру на экран без дополнительной обработки. при этом информация будет вполне читабельно форматирована.

пост получился и так уж слишком большой.. так что о том, что ещё собираюсь сделать напишу в следующем.

p.s.
перечитал и заметил, что пишу то "тэг", то "тег".. а как правильно?

21 апр. 2009 г.

Joystick 0.5

"Видение победителя выплыло из последних минут предрассветного хаоса..." - на часах 5:18,, а я бьюсь со своим кремниевым зверем...

машина повержена - я обернулсе победителем!
итак,, Joystick стал теперь полноценным Монадическим Трансформером. а это ещё один шаг на пути к успеху абстракции.

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

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

13 апр. 2009 г.

Joystick is online

Не могу не написать о том, что ко мне вернулось вдохновение и я вновь воскресил Джойстика, как это уже происходило несколько раз.

Joystick - это чат-бот, которого я пишу на хаскелле. изначально он был просто ботом, с которым можно было пообщаться на своём компе. он учится говорить у своих собеседников, запоминая как они строят предложения. система более чем примитивная,, но иногда она выдавала такие перлы,, что не восхищаться им было сложно.
потом darling-kicks написал для него интерфейс для работы через вконтакт (на перле). и Джой там какое-то время жил и был всем доволен, общался со всеми желающими через сообщения или надписи на стене. у него там появились друзья и почитатели,, те кто с ним регулярно общался. мы понемногу устраняли всякие неисправности и улучшали его,, и интересно, что администрация не засекла что его (потому что он достаточно естественно себя вёл),, хотя в то же самое время у моего знакомого забанили вконтакте двух самописных ботов и стали строже следить за тем, что многие пишут "недостоверную информацию" (: Джой как и в фильме "испоганил все их планы".
потом всё постепенно как-то заглохло.. во-первых потому что с ростом лексикона бредовость его мыслей возрастала экспоненциально,, а все хотели с ним болтать как с человеком - никто не хотел его учить, как надо говорить,, во-вторых изменился api контакта и перл-интерфейс перестал работать. и переделывать его не было большого смысла - нужны были качественные изменения.
новая реинкарнация Джойстика из Марракеша была реализована мной уже под irc полностью на хаскелле. было это в августе прошлого года на chaos constructions - атмосфера располагала к тому, чтобы что-нибудь эдакое сделать - впрочем и предыдущая версия была в значительной степени сделана на этом мероприятии годом раньше.
новая irc-версия была полностью переделана и более или менее нормально работала,, но особой популярностью не пользовалась. видимо потому что наиболее активные собеседники - люди далёкие от "хакирования",, а в irc собственно в основном либо те, кто там уже очень давно,, либо те, кто просто по жизни увлекается такими штуками.
а вот на прошлой неделе было такое мероприятие под названием sun teсh days - тоже посиделки для программистов организованные Sun. и снова это вдохновило нас с darling-kicks на новые свершения в старых начинаниях.
итак новая, последняя на данный момент версия Джоя - это старая начинка из irc-версии в новой обертке jabber-интерфейса. нашлась библиотечка для хаскелла про джаббер и оказалось очень просто перенести то, что было готово.
теперь Джой может работать как нормальный jabber-bot и всё в общем-то в этом смысле хорошо. к тому же джаббер в последнее время стал довольно популярен и весьма доступен. так что можно расчитывать на нормальную аудиторию собеседников.

но интерфейс, такой или эдакий, это ещё четверть дела. а самое интересное в том, как он устроен изнутри: как он учится, как "думает" и как формулирует свои мысли.
и так как с jabber частью делать особенно нечего, я хочу заняться вплотную перерождением мозга Джойстика и сделать какую-то более интересную и теоретически продвинутую модель. так что в ближайшее время буду разбираться со всякими хитрыми хаскеллевскими библиотеками про анализ естественных языков, искуственный интеллект, марковские цепи и т.д. и т.п.
а про то, что я решу использовать и как я буду это делать, я думаю я тут ещё более или менее подробно напишу.

в то же самое время darling-kicks параллельно со мной занимается разработкой Джоя на перле. и надо заметить со своими оригинальными идеями. браво, дружище!
посмотрим что у нас выйдет...

да и самое главное! как его теперь можно найти:
нужно в своём джаббер-клиенте, добавить пользователя 0xjoystick@jabber.org - и когда он будент онлайн, с ним можно поболтать (;

p.s. не надо думать, будто id3project умер. он вошёл в рутинную стадию документации и тестирования, а всякая рутина как известно убивает творческие порывы. поэтому через некоторое время, поиграв с Джойстиком, я вернусь и с новыми силами доделаю то что задумал. обязательно доделаю. если брошу на пол-пути - будет не просто обидно, это будет стыд и срам. я себе этого не прощу. (;