Свалка идей. Возможно фантастических. Возможно реальных.

printf/scanf реализованные на camlp4

Цель - скорость, полностью избавиться от парсинга форматной строки в рантайме.

См. http://caml.inria.fr/pub/ml-archives/caml-list/2002/04/1d6d46bf8aa8f5fa8ac3bdac54bf96d1.en.html

generic print

При первом проходе - синтаксически заменять все print expr на let _x = expr in () и после компиляции смотреть тип expr через дамп TypedTree или через -annot. При втором проходе используя информацию о типах синтаксически собирать принтер всего выражения из принтеров составных частей (которые определены для примитивных типов и типов из stdlib) и подставлять этот конкретный принтер в исходный код. Возможно задача сводится к автоматическому выводу нужного аргумента (типа) для Show.show<\_\> (deriving) и полуавтоматической реализации модулей Show\_ для существующих типов (из stdlib).

Косяки :

Пофиксить thread pool в JoCaml

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

async actions a la F\#

Чисто синтаксически преобразовывать

let! sock = connect addr in
let! ping = read sock in
let answer = "pong " ^ ping in
let! () = write sock answer in
()

в

connect_async addr (fun sock ->
read_async sock (fun ping ->
let answer = "pong " & ping in
write_async sock answer (fun () -> ())))

Все \*\_async вызовы обрабатываются через один общий асинхронный менеджер.

Вопросы:

нотификация о перемещении для custom\_val

Дополнительный callback в структуре custom\_ops для нотификации о смене адреса value при сборке мусора (два случая - minor-\>major и compaction), позволит сишным биндингам явно сохранять указатель на ocaml значения и обновлять его при (редком) перемещении.

см. http://chatlogs.jabber.ru/ocaml@conference.jabber.ru/2010/08/06.html\#18:54:04.836275


ocaml on-disk datastructures

Есть применение для такой штуки: есть файл, в котором раскидана окамловская структура данных, по которой можно ходить с помощью определённых функций, менять, дописывать, мусорособирать по-тупому. Персистентность, что ли. Что-то типа ancient, только в файле. Либо, то же самое, что маршаленная огромная структура данных, только без маршаллинга всей структуры туда-сюда. Кеш -- либо дать ОС делать свою работу, либо сделать очень тупой кеш (основанный на хинтах типа "пока эта функция выполняется, лучше это значение / эту страницу подержать в памяти чуток"). Сборку мусора уже кое-как асилил (завести второй файл, куда скидывать живые данные вплотную, заменяя в первом файле смещения значений на те, которые во втором, ставя признак "значение в другом файле", однако есть сложности с изменяемыми значениями. Либо, вариант, вместо сборки мусора поддерживать free list). Не продумал flash-friendly writes, чтобы если оно на флешке, то флешка не угибалась раньше времени. Вообще, надо почитать про "on-disk data structures", в том числе в применении ко всяким ssd. То есть, если в персистентную структуру положить какое-нибудь type tree 'i 'a = [ Node of 'a | Tree of 'i and 'i and list (tree 'i 'a) ] (где в конструкторе Tree будут минимальное значение ключа в поддереве, максимальное, и собственно поддерево), то получим что-то типа имплементации btree поверх файлов. (тип взят от балды.) Если кому-нибудь такое/подобное тоже надо будет -- давайте думать вместе.

Пока принцип можно сделать тупым: файл, в который только дописываются новые значения. Может потом учесть что-то про мусорщика, чтобы дописывать с тегами. Может наоборот, учитывать про free list. Надо думать. По первым прикидкам, можно оформить модуль для сериализации значений (вдруг кому не нравится Marshall, это нормально), и модуль для работы с персистентными значениями:

module Pers
  =
    struct
      type pers 'a;
      value get : pers 'a -> 'a;
      value modify : pers 'a -> 'a -> unit;
    end

Кроме того, вертится в голове кое-что на тему того, что можно из рекурсивной структуры вида type ty 'a = { selfref1 : ty 'a } сделать структуру type ty_pers 'a = { selfref1 : ty_pers 'a }, надо подумать про http://alain.frisch.fr/soft#recursive или подобное. В общем, если структура является функтором (в смысле теории категорий), то её можно легко превратить в персистентную, просто отобразив её функцией, превращающей окамловское значение в смещение этого же значения, сериализованного в файле. Подумать, стоит ли вообще работать с не-функториальными структурами данных. Из них сходу -- абстрактные структуры данных, с которыми работать не можем никак, без их помощи (без сериализатора, например), и функциональные значения, которые точно не нужно писать на диск.

Кроме того, надо как-то учитывать корневые значения, хотя бы для сборки мусора. Например, оформить mutable single-linked list, в хвост которого дописывать новый узел, хранящий новое корневое значение (вероятно даже средствами самой "библиотеки" -- хранить в файле "type roots = { val : Obj.t ; next : mutable option roots }", хотя подумать про типы -- нужно ли / можно ли туда тащить Obj.). Конечно, потребуется знать, где последний узел списка хранится (а это, вероятно, дофига seek+read, но можно оптимизировать), но зато для записи -- весьма дружественная структура, перезаписывает не один фиксированный блок файла, а каждый раз разный.

И надо учитывать какие-то именованные значения для взятия конкретных значений из файла, типа get_named_value : string -> pers 'a; с пользовательским типом 'a. Как input_value например. Либо подумать про сериализацию вообще, как безопасней сделать её, но чтобы в случае "НАДА СКОРАСТЬ" не терять особо. Подумать, как совместить сборку мусора с записью. Например, если нужно записать страницу, но не прямо сейчас, и вскоре нужно записать в файл новое значение, то смотреть, можно ли его поместить на эту страницу, которая всё равно уйдёт на диск.

Подумалось, как можно оптимизировать перезапись блоков для flash-friendly writes. Два варианта: 1. оформить корневые значения в виде mutable single-linked list, и добавление нового корневого значения вызовет запись в двух блоках: в хвосте, где nil, и в непосредственно новом блоке (плюс к тому, нужны какие-нибудь несложные индексы для быстрой навигации по данному списку). 2. постановить, что последний блок файла (4096 байт, например) всегда содержит служебную информацию (например, указатель на первое и последнее корневое значение), и при расширении файла сначала рисовать новый "последний блок", а затем уже писать в файл данные. Либо так: последние 4 байта содержат размер этого блока, перед ними идёт блок, остальное -- значения. И можно оптимизировать запись тем, что выделять сразу много блоков, а не двигать последний блок каждый раз на 4кб.