metaclass: (Default)
metaclass ([personal profile] metaclass) wrote2010-10-13 06:39 pm
Entry tags:

Дай дураку F# стеклянный..

Домудрился с вложенными ленивыми секвенсами вперемежку с обращениями к БД до такой степени, что сломал компилятор F#, похоже. Во всяком случае, он у меня теперь умудряется сделать Dispose команде доступа к БД до того как начнет генерить последовательность из нее. Причем, что удивительно - не всегда, а только при определенном паттерне обращения к другим командам.


2010-10-13 21:43:20,944 [1] DEBUG StartupCode$ModelGen.$FirebirdReader newCmd   cmdForeignKeys 61724767 Open
2010-10-13 21:43:20,944 [1] DEBUG StartupCode$ModelGen.$FirebirdReader newCmd   cmdForeignKeyFields 18651996 Open
2010-10-13 21:43:20,944 [1] DEBUG StartupCode$ModelGen.$FirebirdReader Disposed cmdForeignKeyFields cmdForeignKeyFields 18651996
2010-10-13 21:43:20,944 [1] DEBUG StartupCode$ModelGen.$FirebirdReader Disposed cmdForeignKeys cmdForeignKeys 61724767
2010-10-13 21:43:20,944 [1] DEBUG StartupCode$ModelGen.$FirebirdReader cmdForeignKeyFields.ExecuteReader 18651996 ForeignKeyFields FK_ForeignKeys
2010-10-13 21:43:20,944 [1] FATAL CurrentDomain_UnhandledException
System.InvalidOperationException: Connection must be valid and open



Однозначно, что ленивость+внешние ресурсы это не совсем то, что следует делать, да и отладке это не подлежит в принципе, ибо монады. Но как превратить это дело в fold-like алгоритм, хрен его знает, да еще с учетом того, что там внутри не просто итератор по плоским записям, а внутри этих записей еще вложенные итераторы, а из них ссылки на элементы из других итераторов, в общем, ад тот еще.
Вот еще смех будет, если это не в F# проблема, а в ADO.NET провайдере Firebird.

PS: Судя по всему, все хорошо и пень все таки я - таки ленивые вложенные итераторы можно использовать только вложенно, а не так как я - сначала пройтись по внешнему, найти нужную запись, а потом из нее читать вложенные. Адекватный вариант - сделать их неленивыми. Обычно в этом помогает Seq.cache, но тут он, похоже, тоже вызывается в неподходящий момент.

PPS: Ухуху, и решение в этом случае действительно, как и советуют гуру ленивости - перевернуть все в fold-like алгоритм, передав две функции - одну для fold внешнего итератора и одну для fold внутреннего (и вроде в общем случае, еще две - одну которая будет из внешнего итератора и состояния делать начальное состояние для fold внутреннего, и вторая будет комбинировать результат от fold внутреннего итератора и состояние внешнего).
Это получается, что для fold в случае вложенных итераторов количество передаваемых параметров-функций прилично возрастает: по одной функции на каждый итератор в иерархии и +2 на каждый случай вложенного итератора, причем у самих этих функций количество передаваемых в них параметров тоже особой радости не доставляет.
Зато соответствующим набором таких функций, судя по всему, можно вычислить произвольную функцию от базы данных, представленной в виде набора разнообразно вложенных итераторов :)

[identity profile] gds.livejournal.com 2010-10-13 08:11 pm (UTC)(link)
кстати, я сейчас в процессе портирования олеговских iteratees (например, talk notes) на окамл. Если чо, как проверю это в деле, смогу перевести в ocaml original syntax, а далее, если F# умеет custom infix operators, будет почти халява перевести его на F#. Поэтому стоит подумать, помогут ли тут iteratees.
Они -- почти тот же самый fold (в том числе вложенный), только с кучей гарантий (по хендлам, по памяти, по ограничению внутренних итераторов(?) внешними). И есть преимущества над fold -- не надо показывать наружу начальное состояние, не надо выдумывать ничего, чтобы прервать выполнение, плюс относительно-прозрачная обработка ошибок.
(во многое пока не вникал, но это точно лучше, чем прямой ввод-вывод (как в императивщине), лучше, чем ленивый ввод-вывод (как IO в х-е), и лучше, чем fold поверх потоков с данными.)

[identity profile] metaclass.livejournal.com 2010-10-13 08:23 pm (UTC)(link)
В общем, оно как раз тут и нужно, но мне пока мозга не хватает осилить :)

[identity profile] gds.livejournal.com 2010-10-13 08:44 pm (UTC)(link)
+1. Но я -- бездумно портирую! Я идиот и я люблю гусей!11111
А заодно я при портировании понимаю, что и как Олег сделал. И я ещё комментатор. Дополняю документацию для тех, кто функциональщину знает, но не всегда понимает интуитивно монады, хитровыебанные инфиксные вызовы по шесть функций за раз, при их неочевидности и ёбаной перегрузке операторов из ёбаных тайпклассов, и навожу там порядок. Чтобы простой быдло-ML кодер смог сделать свой вполне защищённый веб-сервер за 21 день (ну или что-то типа того; 20 дней на iteratees).

[identity profile] lionet.livejournal.com 2010-10-14 04:09 am (UTC)(link)
Ты презентацию посмотрел уже, которая с комментариями? Если "да", то я удивляюсь, что там осиливать-то?

[identity profile] clayrat.livejournal.com 2010-10-14 12:40 am (UTC)(link)
о, интересно