metaclass: (Default)
metaclass ([personal profile] metaclass) wrote2010-03-13 11:51 am
Entry tags:

Ссылка с planet haskell, IO monad

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

В этом плане я не совсем понимаю, почему в хаскеле эта монада - одна на все виды взаимодействия с внешним миром? Например, с моей точки зрения чтение и запись файлов совершенно отличается от обращения к серверу БД, что в свою очередь отличается от разговора с пользователем в консоли, что опять же отличается от взаимодействия в GUI, итд. Еще можно вспомнить работу по сети, работу с COM-портами, FFI итд.

Предположительно, было бы гуманно дать программистам возможность самостоятельно делать IO-подобные монады и расселить разные виды взаимодействия по разным монадам, заодно как-то прикрутить к этим монадам некие атрибуты на тему ленивости и порядка вычислений - т.е. например, запись в лог без разницы в каком порядке будет делаться и вообще должна вычисляться только тогда, когда это значение кому-то интересно.

Это я как-то размышлял на тему, "как бы выглядел хаскель, встроенный в СУБД в качестве языка запросов". Я с трудом могу перейти от размышления над обычной программой в стиле "запустили, ввели данные, получили результат" к постоянно запущенной программе, управляемой событиями типа "сервер, ждет запроса от клиентов" или "GUI приложение ждет нажатия кнопки пользователем".
И от "программа читает файл с состоянием, обрабатывает запрос и сохраняет файл обратно" к "программа живет с внутренним состоянием, которое обрабатывается интегрированным в компилятор/виртуальную машину/интерпретатор движком БД.
Реализация IO мешается в голове, а для СУБД нужна была бы еще одна монада (а может и не одна), отражающая внутреннее состояние, упорядочивающая действия с записями, транзакциями и взаимодействием между различными пользователями, лезущими к одним и тем же данным).

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

[identity profile] thesz.livejournal.com 2010-03-13 01:24 pm (UTC)(link)
Это получится, как с уникальными типами Clean.

Ради прикола попробуй сделать чтение и запись файла вперемешку с выдачей запроса БД в твоей вселенной, где есть DBM и FileM.

А сокеты, сокеты куда денешь? В FileM или в SocketM?

Получится, что read будет методом класса HasRead: class Monad m => HasRead m where read :: Handle -> m [Char]

И на ровном месте получаем нехилое усложнение.

Кстати, map и ++ для списков стоят отдельно вот уже сколько лет потому, что новичку будет трудно объяснить, почему же map это функтор, а ++ - операция моноида.

Так и здесь - IO монолитно потому, что проще стартовать.

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

[identity profile] nealar.livejournal.com 2010-03-13 01:38 pm (UTC)(link)
А сокеты, сокеты куда денешь?
POSIX - значит, чтение-запись в File, открытие - лифт из Socket в File.
Но это слишком простой вопрос. Если копать всерьёз, то мы наткнёмся на действительно сложные вопросы дизайна. Потому IO монолитно.
Иещё, не забываем про то, что мы - thread-aware, то есть, мы должны уметь не только (>>=) и return делать, но ещё и сообщать RTS о возможных изменениях состояния потока.