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 как бы таскает с собой "состояние внешнего мира". А это самое состояние - оно ни разу не монолитное, и его, если по хорошему, нужно разбить на несколько частей ("пользователь", "файлы", "базы данных", "сторонние системы").
ext_615659: (Default)

[identity profile] akuklev.livejournal.com 2010-03-13 12:23 pm (UTC)(link)
IO-монада просто реализует (семантически необходимое) проведение по цепи выполнения объекта "State of the World". Более грамотно было бы конечно создать класс монад этого типа, позволяющих создавать монады, отвечающие разным аспектам этого самого State of the World. В первую очередь для различения State of the External World и внутреннего (сиречь инкапсулированного) состояния мутабельных объектов. Все такие специализированные монады этого типа теоретически можно реализовать поверх общей IO, но практически, к сожалению, неудобно.

[identity profile] nealar.livejournal.com 2010-03-13 12:32 pm (UTC)(link)
При доступе к БД, вместо State of the World там должон стоять State of Database, если делать по уму.
но практически, к сожалению, неудобно
Ага.
ext_615659: (Default)

[identity profile] akuklev.livejournal.com 2010-03-13 12:33 pm (UTC)(link)
Именно так. Я даже примерно знаю, как надо было сделать, чтобы на практике было удобно. Но сейчас уже поздно (в смысле, для Хаскелла).

[identity profile] nealar.livejournal.com 2010-03-13 01:10 pm (UTC)(link)
Не поздно. Он ещё не настолько популярен, и haskell == GHC - это ещё не родовое проклятие, а только тревожный симптом.

[identity profile] thesz.livejournal.com 2010-03-13 01:16 pm (UTC)(link)
При доступе к БД, вместо State of the World там должон стоять State of Database, если делать по уму.

Который зависит от неизвестной нам части State of the world. Иными словами - просто зависит от state of the world. И получается, что смысла в отдельном State of the Database нет.

[identity profile] metaclass.livejournal.com 2010-03-13 01:22 pm (UTC)(link)
В идеале, СУБД зависит только сама от себя. Взаимодействия с другими клиентами, блокировки, транзакции - это все включено в State of Database.
Во всяком случае, в моих проектах именно так.

[identity profile] thesz.livejournal.com 2010-03-13 01:28 pm (UTC)(link)
У тебя ключевое слово "в идеале". В идеале у тебя получится БД, что хранит ().

Вот смотри: работа БД может переполнить какой-либо ресурс? Например, память или дисковое пространство? Или сокеты. Так, что другим "монадам" не останется, где выполнять свои действия. Если может, то БД неявно взаимодействует с другими монадами, через неизвестный нам канал, спрятанный в State of the world. Если нет, я хочу видеть реализацию этого дела.

Если говорить практически, то сделай монаду для БД по образу и подобию монады транзакционной памяти или рисования в холсте Cairo.

Попробуй с этим поработать. ;)

[identity profile] nealar.livejournal.com 2010-03-13 01:33 pm (UTC)(link)
Чистая функция тоже меняет флаги процессора, показания счётчика реального времени и т.д. Переполнить с помощью чистого вычисления ресурс "память", испортив жизнь других "монад" - запросто. Чем не аналогия?

[identity profile] thesz.livejournal.com 2010-03-13 01:48 pm (UTC)(link)
Ну, да.

Смотри, в GRIN чистые вычисления транслируются в монадический код.

Как ты думаешь, поверх чего работает эта монада? Если там разница между int_plus и launch_missiles?

[identity profile] nealar.livejournal.com 2010-03-13 02:38 pm (UTC)(link)
Я не знаю, что такое GRIN. И уже утерял нить.
Моя мысль была: DBMonad сделать можно и нужно. Но. Монолитное IO тоже имеет право на жизнь, и это можно обосновать.

[identity profile] thesz.livejournal.com 2010-03-13 02:55 pm (UTC)(link)
Я столько раз говорил про GRIN, что мне больно слышать такие слова от столь давнишнего читателя, как ты. ;)

Одна моя мысль такая: часть функциональности базы данных не зависит от IO. Но часть - зависит. Поэтому взаимодействие между FileM и DBM будет, скорее всего, через эту самую IO.

Другая моя мысль такая: DBM и FileM можно сделать вот уже сейчас. И делают, если это действительно нужно (работа с графикой и обработка сигналов в gtk2hs, или транзакционная память, например). Только это привнесёт такую кучу проблем...

(no subject)

[identity profile] nealar.livejournal.com - 2010-03-13 15:11 (UTC) - Expand

(no subject)

[identity profile] thesz.livejournal.com - 2010-03-13 15:18 (UTC) - Expand

(no subject)

[identity profile] nealar.livejournal.com - 2010-03-13 15:37 (UTC) - Expand

(no subject)

[identity profile] thesz.livejournal.com - 2010-03-13 15:49 (UTC) - Expand

(no subject)

[identity profile] nealar.livejournal.com - 2010-03-13 15:56 (UTC) - Expand

(no subject)

[identity profile] nivanych.livejournal.com - 2010-03-13 17:30 (UTC) - Expand

(no subject)

[identity profile] thesz.livejournal.com - 2010-03-13 17:57 (UTC) - Expand

(no subject)

[identity profile] nivanych.livejournal.com - 2010-03-13 18:06 (UTC) - Expand

(no subject)

[identity profile] thesz.livejournal.com - 2010-03-13 19:18 (UTC) - Expand

(no subject)

[identity profile] thesz.livejournal.com - 2010-03-19 10:16 (UTC) - Expand

(no subject)

[identity profile] nivanych.livejournal.com - 2010-03-13 17:36 (UTC) - Expand

(no subject)

[identity profile] thesz.livejournal.com - 2010-03-13 17:52 (UTC) - Expand

(no subject)

[identity profile] nivanych.livejournal.com - 2010-03-13 18:15 (UTC) - Expand

(no subject)

[identity profile] thesz.livejournal.com - 2010-03-13 19:29 (UTC) - Expand

(no subject)

[identity profile] metaclass.livejournal.com - 2010-03-13 18:56 (UTC) - Expand

(no subject)

[identity profile] thesz.livejournal.com - 2010-03-13 19:27 (UTC) - Expand

(no subject)

[identity profile] nealar.livejournal.com - 2010-03-13 20:42 (UTC) - Expand

(no subject)

[identity profile] thesz.livejournal.com - 2010-03-13 20:46 (UTC) - Expand

(no subject)

[identity profile] nealar.livejournal.com - 2010-03-13 22:05 (UTC) - Expand

(no subject)

[identity profile] thesz.livejournal.com - 2010-03-13 23:00 (UTC) - Expand

(no subject)

[identity profile] nealar.livejournal.com - 2010-03-13 23:25 (UTC) - Expand

(no subject)

[identity profile] thesz.livejournal.com - 2010-03-14 00:09 (UTC) - Expand

[identity profile] voidex.livejournal.com 2010-03-13 07:34 pm (UTC)(link)
> Переполнить с помощью чистого вычисления ресурс "память", испортив жизнь других "монад" - запросто
Как?

не понял вопроса

[identity profile] nealar.livejournal.com 2010-03-13 08:41 pm (UTC)(link)
В stack overflow загнать чистым выражением как?

Re: не понял вопроса

[identity profile] voidex.livejournal.com 2010-03-14 08:45 pm (UTC)(link)
Ну, чистое выражение надо где-то начать вычислять.
Если мы вычисляем его в IO, и в IO же какие-то проблемы с памятью - беда беда. А если начали вычислять в BD, а в IO беда с памятью, а упало всё равно в BD, то что-то не так в датском королевстве.

[identity profile] blacklion.livejournal.com 2010-03-13 09:04 pm (UTC)(link)
Тупо породить список больше памяти. Вчера дали гиг — влезло. Сегодня дали полгига — не влезло. Программа чисто функциональная. Вчера работала сегодня — нет. Упс.

[identity profile] voidex.livejournal.com 2010-03-14 08:49 pm (UTC)(link)
Чтобы список породить, его надо где-то вычислить. Если в IO дали мало памяти и упало - то всё логично. А если в IO дали мало памяти, а упало в монаде BD, то уже нелогично.
Вот если у нас runBD :: BD a -> IO a, тогда наверное логично.
Но я вообще идею поста не очень понял. Т.е. саму идею понял, но детали очень важны, а их нет.

(no subject)

[identity profile] blacklion.livejournal.com - 2010-03-15 07:15 (UTC) - Expand

(no subject)

[identity profile] voidex.livejournal.com - 2010-03-15 11:53 (UTC) - Expand

(no subject)

[identity profile] blacklion.livejournal.com - 2010-03-15 13:20 (UTC) - Expand

(no subject)

[identity profile] voidex.livejournal.com - 2010-03-15 15:12 (UTC) - Expand

[identity profile] metaclass.livejournal.com 2010-03-13 01:42 pm (UTC)(link)
Умерший диск, переполнение диска или обрывы сети это все подвиды одного состояния "гамон всему, зовите сисадмина". В базах данных в норме низкоуровневые физические подробности изолированы от логической работы с данными, соответственно с физическими тонкостями разбирается только SYSDBA. Т.е. внутри то базы может быть и FileIO но снаружи это никого не волнует никак.
По логике, тогда получается, что нам нужен способ переселиться из FileIO в DBIO где-то внутри СУБД, т.к. внешним клиентам DBIO совершенно не важен.

[identity profile] thesz.livejournal.com 2010-03-13 01:50 pm (UTC)(link)
Это всё ты можешь сделать вот уже прямо сейчас.

И люди так и делают. В третий раз намекну на транзакционную память и на рисование в Cairo. ;)

[identity profile] metaclass.livejournal.com 2010-03-13 12:40 pm (UTC)(link)
Да, точно. Я как раз насчет разделения State of the World на отдельные аспекты и думал, но забыл и не написал про это :)

[identity profile] nealar.livejournal.com 2010-03-13 12:30 pm (UTC)(link)
Патамушта:
1. IO жостко связывается с многозадачностью (в каком языке самые зеленые треды, ага?). Чтобы обращение одного потока к БД, _ВНЕЗАПНО_ не застопорило все остальные.
2. Инерция мышления. По уму, надо бы эти вещи разгрести и сделать _чистые_ функции доступа к БД, специальную низкоуровневую монаду для компортов, монаду Филе, которая делает POSIX-образный доступ к файлам и т.п.

[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 о возможных изменениях состояния потока.

[identity profile] migmit.vox.com (from livejournal.com) 2010-03-13 02:20 pm (UTC)(link)
> было бы гуманно дать программистам возможность самостоятельно делать IO-подобные монады

А какие с этим проблемы?

Можно писать интерпретирующие монады. Можно ограничивать IO. Можно делать что-то среднее. Простор для творчества.

[identity profile] nivanych.livejournal.com 2010-03-13 05:29 pm (UTC)(link)
Разбить-то можно.
Но как ты этими частями общаться между собой будешь?
Кучу трансформеров городить?
Впрочем, тут тов.[livejournal.com profile] migmit придумал чего-то интересное, надо посмотреть подробнее.
В любом случае, разработчики посчитали, что так, как сейчас, будет практичнее.
Если тебе надо, сам и делай кучу монад на твои жизненные случаи ;-)
Они очень даже бывают, конечно.
Сергей тоже вот правильно говорит.

[identity profile] http://users.livejournal.com/_slw/ 2010-05-18 10:38 am (UTC)(link)
это потому что авторы были испорчены библиотекой турбовижен, которая все -- потомок одного класса!