thedeemon: (Default)
[personal profile] thedeemon
Когда делаю для себя на Окамле что-то интерактивное, то обычно делаю веб-интерфейс. Нашел в интернетах простенький веб-сервер в 200 строк (из них половина - перечисление кодов ошибок HTTP) - thumper, портировал под винду (реализовав нехватавшую функцию из модуля Unix), дописал разбор параметров и POST запросов. Устроено там все было очень просто и по-функциональному: для нужных путей регистрируются обработчики, являющиеся вполне себе чистыми функциями - параметры запроса на входе, заголовки и тело ответа на выходе. Этого вполне хватало, но вот пришел день, когда понадобилось обрабатывать много данных и выводить прогресс выполнения. И тут всплыл закон дырявых абстракций.
Как говорят классики, чистое функциональное программирование - это программирование посредством математических функций. Такие функции зависят только от своих параметров и описанных выше значений (эту часть обычно забывают упомянуть, кстати) и возвращают одно значение, больше ничего не делая, т.к. делать-то они ничего и не могут - функция есть просто отображение, математическая конструкция. В математике просто нет такого понятия, как время вычисления функции, там если она описана, то считай, что для всех возможных входных значений результат уже известен. В этом чистая математика разительно расходится с компьютерной действительностью, где присутствует еще одно измерение - время, отчего и возникает столько проблем с временем выполнения программ на чистых языках. Но это я отвлекся.
В данном случае я поступил следующим образом. Раньше обработчик запроса возвращал тело ответа в виде строки. Теперь же он возвращал значение типа

type content_t = ContString of string | ContEnum of string Enum.t;; 

Т.е. это либо строка, как раньше, (чтобы старые обработчики сильно не менять), либо ленивая последовательность строк. Ее сервер выводит, делая flush после каждой порции. Долго работающая операция в моем случае меняла состояние программы - загружала из кучи файлов данные, которые использовались в последующих запросах. Получилось, что загрузка данных - это сайд-эффект, а возвращаемое значение - постепенное отображение прогресса загрузки. Выглядело это примерно так:

let files_work_enum = files |> List.enum |> Enum.mapi (fun i fname ->  
    res_list := (parse_file !g_dics fname) :: !res_list; (* time consuming operation *) 
    let percent = (i+1) * 100 / nfiles in 
    Printf.sprintf "<script>setPercent(%d);</script>" percent) in ...

Т.е. обработчик запроса возвращает веб-серверу последовательность отложенных вычислений. Веб-сервер последовательно по ней проходится, отдавая результаты пользователю, в результате прогрессбар ползет по мере обработки данных. Все работает, но благодаря тому, что само вычисление стало побочным эффектом. Вот мне интересно, а как такая задача решается в православном чистом ФП?

Date: 2009-09-23 10:37 am (UTC)
From: [identity profile] vlasovskikh (from livejournal.com)
Спасибо за решение проблемы с аутентификацией по OpenID.

Profile

thedeemon: (Default)
Dmitry Popov

December 2025

S M T W T F S
 12 3456
789101112 13
14151617181920
21222324252627
28293031   

Most Popular Tags

Page Summary

Style Credit

Expand Cut Tags

No cut tags
Page generated Jan. 28th, 2026 01:02 am
Powered by Dreamwidth Studios