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] nealar.livejournal.com 2010-03-13 03:11 pm (UTC)(link)
Поэтому взаимодействие между FileM и DBM будет, скорее всего, через эту самую IO.
Подсмотрено в hmatrix: работа с внешней библиотекой линейной алгебры идёт через блоки памяти, которые выделает Foreign.Alloc. То есть, IO. Но. Когда функция "посчитать" отработала, отдала всё, что запросила, с точки зрения стороннего наблюдателя - меня, она выглядит вполне чистой: если мы её вызовем повторно, она вернёт то же самое, и ничего не испортит. Вероятно, поэтому, авторы hmatrix завернули её в unsafePerformIO. Лично я, когда переписывал их код для своих целей, так делать не стал. Но, мне кажется, такой подход имеет право на жизнь. Если "что-то пошло не так", то и launch_missiles и int_plus одинаково плюются исключениями.
Конечно, чем сложней задача, тем сильней протекает изоляция, и тем сложней считать, что unsafePerformIO делать честно.
Вторую мысль поддерживаю всеми руками. Сомневаюсь, что для задачи [livejournal.com profile] metaclassа это действительно нужно, но такая библиотека нужна, как proof of concept. Насчёт того, что STM приносит какие-то большие проблемы - слышу первый раз. Интересно.
Касательно GRIN: если бы у меня хватало времени прочитывать все твои ссылки на нерусские статьи, я бы уже был офигеть каким умным. Те же CSP и π-calculus в моё поле зрения попали не помню когда. Всё никак.

[identity profile] thesz.livejournal.com 2010-03-13 03:18 pm (UTC)(link)
>Насчёт того, что STM приносит какие-то большие проблемы - слышу первый раз. Интересно.

Производительность. ;)

Читал обсуждение, что внесение IO действий внутрь STM может её поднять - чтобы не откатываться на верхний уровень транзакции, когда мы можем выполнить некоторые полезные действия с учётом (в голове) того, что ресурс нам недоступен. (примерно, я по памяти)

[identity profile] nealar.livejournal.com 2010-03-13 03:37 pm (UTC)(link)
1. КМК, реализация, когда atomically идёт, пока не натыкается на недоступный ресурс, а потом получает в лоб и откатывается к началу - не единственный способ сделать STM.
2. Первая мысль по поводу "не откатываться на верхний уровень" - надо тоньше на транзакции резать, а не засовывать всю программу в один блок atomically.
3. Вторая мысль - что в STM с рождения есть такой недостаток, и на это нам указываем наличие newTVarIO. Даже у авторов возник случай, когда нам нужно что-то контрабандой протащить за границу монады. А значит, и в реальной жизни где-то такое возникнет.

[identity profile] thesz.livejournal.com 2010-03-13 03:49 pm (UTC)(link)
>1. КМК, реализация, когда atomically идёт, пока не натыкается на недоступный ресурс, а потом получает в лоб и откатывается к началу - не единственный способ сделать STM.

Ух ты!

Расскажи, как!

Да что там "расскажи". Статью пиши, не меньше!

Утри нос всем этим Пейтонам-Джонам. ;)

>2. Первая мысль по поводу "не откатываться на верхний уровень" - надо тоньше на транзакции резать, а не засовывать всю программу в один блок atomically.

Зависит от программы, не так ли?

>3. Вторая мысль - что в STM с рождения есть такой недостаток, и на это нам указываем наличие newTVarIO. Даже у авторов возник случай, когда нам нужно что-то контрабандой протащить за границу монады. А значит, и в реальной жизни где-то такое возникнет.

Это не то исключение, что ты ищешь. Это сделано для unsafePerformIO.

[identity profile] nealar.livejournal.com 2010-03-13 03:56 pm (UTC)(link)
1. Я подозреваю, что результат будет хуже, чем то, что используется щаз.
2. См. пункт 3. Резать тоньше надо,конечно, но не всегда возможно и не всегда практично. "Случаи разные бывают"
3. Не понял. newTVarIO сделан для того, чтоб TVar можно было отдать в другой поток, ведь forkIO и forkOS - они не в STM работают. А TVar без возможности работы с ним в многих потоках - это какая-то "вещь в себе".

[identity profile] nivanych.livejournal.com 2010-03-13 05:30 pm (UTC)(link)
> Производительность. ;)

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

[identity profile] thesz.livejournal.com 2010-03-13 05:57 pm (UTC)(link)
Однако, в некоторых случаях можно поднять и эту бОльшую производительность. ;)

[identity profile] nivanych.livejournal.com 2010-03-13 06:06 pm (UTC)(link)
Можно, конечно, в некоторых случаях.
Я говорил про какой-то общий подход, что-ли...
А это "можно" будет следовать из специфики задачи.
Хотя, конечно, не помешало бы уметь просто и быстро
подстраиваться к этой самой специфике.

[identity profile] thesz.livejournal.com 2010-03-13 07:18 pm (UTC)(link)
В общем-то завершённый инструментарий STM хотели внести примитив вида tryWithIO :: STM a -> IO b -> STM a, который выполнял бы первое действие и, если произошёл откат, выполнял бы второе действие перед возвратом к попытке выполнить первое.

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

Не знаю, прошло ли это куда-нибудь, или нет. Пока не видно.

[identity profile] http://users.livejournal.com/_navi_/ 2010-03-19 05:45 am (UTC)(link)
ну иногда можно вообще, жёстко запланировать время работы каждого потока и заранее гарантировать отсутствие race condition на разделяемых данных. Вот только практично такое очень редко.

[identity profile] thesz.livejournal.com 2010-03-19 10:16 am (UTC)(link)
То, о чём я говорю (и о чём говорилось в письме SPJ, которое я не могу найти) - это не планирование. Это выполнение действий, которые позволят несколько продвинуться в процессе достижения конечной цели даже в случае отката транзакции.