to post messages and comments.

← All posts tagged Haskell

С управлением настройками планшетов wacom в kde всё немного грустно. В KDE4 есть более-менее нормальный модуль для этого, но 4е кеды вроде как уходят в прошлое. В Plasma 5 модуль есть, но недопортирован и хромает на обе ноги.
При этом ни тот, ни другой (и, насколько я знаю, гномовский тоже?) не умеют автоматом переключать профили настроек при переключении окон. И ещё они не умеют управлять режимами кольца на планшете (intuos pro).
А если у вас не кеды и не гном, а какой-нибудь lxde, то всё совсем грустно — остаётся только баш-скриптами xsetwacom запускать.
В итоге глюки кде-шного демона довели меня до того, что я сел и написал свой.
github.com
Тут есть несколько вещей:
* Пакет wacom-daemon содержит библиотеку, в которой реализована основная часть логики, и запускалки для этой библиотеки. hswcmcli — тестовая утилита, можно например с командной строки профили планшета переключать. hswcmd — демон, работающий на основе своего конфига (в yaml-формате), умеет автоматом переключать профили.
* Пакет xmonad-wacom содержит модули для автоматического переключения профилей настроек планшета при переключении текущего окна для XMonad. Там есть примеры конфигов xmonad. Поддерживается как интеграция с KDE-шным демоном через dbus, так и самостоятельная работа при помощи библиотеки wacom-daemon. Ещё показывает сообщения о перелкючении профилей через libnotify.
Всё это работает так: запускается демон (в случае xmonad — отдельный поток в рамках самого xmonad, в случае hswcmd — в нём), который помнит текущий профиль настроек, через udev отлавливает подключение планшета и при этом запускает xsetwacom с правильными параметрами. Этому демону через хаскельное API можно сказать "поменяй профиль", он запустит xsetwacom и запомнит новый профиль. Пользоваться этим API можно из XMonad (оконный менеджер сам знает, когда окна переключаются) или из hswcmd (он слушает иксовые события переключения окон). Ну или какие-нибудь ещё программы могут ту же библиотеку использовать, теоретически.
Т.е. если используется xmonad, то можно эту штуку интегрировать в xmonad, и больше ничего запускать не надо. Если используется какой-нибудь там опенбокс, то можно при старте иксов запускать hswcmd.
Всё это в процессе разработки и хреново документировано, но если сильно хочется можно пробовать.

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

Main.java: paste.in.ua
Main.hs: paste.in.ua

Наконец-то дошли руки сделать сохранение списка групп чатов из pidgin. А то если pidgin запускался и сразу открывал чаты, то xmonad не успевал к нему подключиться по dbus, чтобы узнать, куда какое окно кидать, и всё кидалось на один воркспейс — некузяво. Теперь если соединения с pidgin нет, то пользуемся данными из файлика, и сохраняем данные в этот файлик, как только получится подключиться.
Текущее состояние: paste.in.ua

Сделал вот ещё одно приложение для «домашней бухгалтерии в командной строке», в стиле ledger или hledger, но лучше :)
gitorious.org
gitorious.org
Умеет:
* Автоматический выбор корреспондирующих счетов по настраиваемым правилам, так что в большинстве случаев достаточно записывать только одну половину проводки;
* Сверку балансов счетов — можно указать, что в данный момент на счёте такая-то сумма, и yaledger автоматически сделает проводку, чтобы его данные сходились с указанными;
* Шаблоны проводок; периодические проводки; автоматическое выполнение проводок при определённых условиях;
* Чтение проводок из нескольких файлов;
* Чтение проводок из форматов CSV и HTML (выписки из телебанков);
* Само собой, работу с разными валютами;
* Учёт курсовой разницы (из-за разницы между курсами купли/продажи)
* Загрузку курсов валют ЦБ РФ;
* Умную обработку дублирующихся записей;
* Несколько отчётов: балансы счетов, обороты по счетам итп.

Всяких штук для компиляции первотега во второтег много. А есть ли какие-нибудь решения, которые бы компилировались сразу в то и другое? Например, пишем код на каком-то ограниченном [E]DSL, потом к этому коду применяем одну из двух функций — runHaskell или runJS, в первом случае запускается нативный хаскелекод, во втором — соответственно жабаскриптокод. Нужна такая штука для синхронизации кода на сервере и клиенте. Простейший пример — валидация формочек. Хочу описать валидацию (нетривиальную) так, чтобы формочка сначала валидировалась в браузере (со всеми js-красивостями), а потом, после приёма сервером — ещё раз валидировалась на сервере по тому же алгоритму, что в браузере. Ну, чтобы защититься от всяких кадров, которые будут post-запросы без всяких js-формочек слать. И при этом не хочу писать один алгоритм два раза на двух языках.

Я думал, это я один такой ненормальный, что делаю что-то из серии hs-java (http://hackage.haskell.org/package/hs-java). Однако, обнаружились некие австрийские студенты, которые (видимо, в качестве диплома или там курсовой) пилят... вот такое: «MateVM is a Java JIT compiler written in Haskell, using already existing libaries, namly `harpy' [1] and `hs-java' [2]». wien.tomnetworks.com

Оно x86-only (не работает на 64-битных платформах), и способно породить dependency hell (так что ставить лучше в каком-нить virthualenv, ато есть шансы навернуть нафиг весь ваш cabal setup), но я таки его скомпилял — оно работает! :) Хелло ворлды там говорит и фибоначчи считает.

К.о. внезапно обнаружил, что в xmonad.hs можно через dbus интегрировать что угодно. Например, сейчас вот интегрировал себе таким образом pidgin: окошки с чятиками раскидываются по workspace-ам в соответствии с группами, заведёнными в pidgin. Потенциально можно ещё чего-нибудь придумывать из этого.

Написал модуль, который позволяет более-менее просто выполнять средствами persistent сложные sql-запросы. На hackage пока не выложил, так что вот исходник:
paste.in.ua
Пример использования: paste.in.ua

Для тех кто не в теме — persistent это такая «ORM» на haskell, используемая в yesod. Её проблема на сегодняшний день в том, что она вообще не умеет делать сложные sql-запросы иначе как «ручками» (с выписыванием запросов в виде строк, аля php). Данный модуль пытается решить эту проблему.

Запостил ещё парочку пакетов на hackage.

1. generic-server: hackage.haskell.org
Очень простой, как в устройстве, так и в использовании tcp/ip сервер. Вряд ли имеет смысл использовать в хайлоаде, но для простых приложений, кажется, самое то.

2. avahi: hackage.haskell.org
Минимальные биндинги к Avahi (реализация zeroconf такая) через DBus. Можно объявить свой сервис (announce) или найти нужный (browse). Больше пока ничего и не умеет.

Мысли по поводу того, что я сделал в hs-java, но проблема несколько более общая.
Есть структура данных (например, описывающая содержимое .class-файла), которая должна представляться в виде бинарного файла (т.е. с сериализацией). В файле многие поля структуры должны представляться в виде указателей куда-то, смещений, индексов в каких-то таблицах итп. Ну, например, в спеке по формату файла указано «поле Name: 4 байта: смещение в файле, где лежит имя класса». После загрузки файла нужно пройтись по всем этим указателям, прочитать соответствующие куски из файла и подставить их на место указателей. При этом структура данных несколько усложняется (вместо указателей появляются сами данные) Вот. А при сохранении файла надо обратно, соответственно, вместо данных вписать указатели. Проблемы это не представляет, но, если структура большая и развесистая, очень легко где-то забыть такое преобразование проделать. В случае хаскеля я вижу 3 способа отобразить задачу на систему типов:

1. Сделать 2 набора типов данных, например BinaryClass и LoadedClass, с очень похожей структурой, но в одном наборе — указатели, а в другом — собственно данные. Ну и функции для преобразования туда-сюда. Хорошо, преобразовать не забудешь — тайпчекер не разрешит. Но 2 почти одинаковых набора типов данных… не очень красиво.

2. Сделать 1 набор типов, но во всех местах, где могут быть либо указатели, либо данные, вписать тип вида Either Word32 SomeDataType. Типов меньше, но это получается похоже на динамическую типизацию, опять можно где-то забыть что-то преобразовать.

3. Самое красивое, кажется. 1 набор типов, параметризованный «типом-флагом». Например,

type family Link stage a
type instance Link Binary a = Word32
type instance Link Loaded a = a

data Class stage = Class {…, name :: Link stage ByteString, …}

такое я в итоге и сделал в hs-java. Хорошо, только тайпчекер не всегда может правильно вывести типы («Link is type-level function and may be not injective…» итп), приходится сигнатуры типов указывать в некоторых местах. И штуки типа … deriving (Eq,Show) не работают, приходится standalone deriving использовать.

Тут меня на днях стало анноить, что в xmonad новому окну всегда передаётся фокус. В результате родился вот такой патч на xmonad core: paste.in.ua
В конфиг добавляется новое поле focusNewWindow — условие, по которому решаем, давать ли новому окну фокус. По дефолту там «return True», т.е. давать всегда — эмулируем обычное поведение. Можно, например, focusNewWindow = className =? "SomeApp" — давать фокус новым окнам только для приложения SomeApp.
Дискасс.