В настоящее время тянуть запрос Джонатаном С. заменить реализацию Data.IntMap
на одно объяснение в this README на основе идей из сообщения в блоге Эдварда Кемта.
Основная концепция, разработанная Джонатаном С., состоит в том, что IntMap
представляет собой двоичное дерево, которое выглядит так (я сделал некоторые небольшие изменения в его развитии ради последовательности):
data IntMap0 a = Empty | NonEmpty (IntMapNE0 a)
data IntMapNE0 a =
Tip !Int a
| Bin { lo :: !Int
, hi :: !Int
, left :: !(IntMapNE0 a)
, right :: !(IntMapNE0 a) }
В этом представлении каждое node имеет поле, указывающее наименьший и наибольший ключ, содержащийся в IntMapNE0
. Использование немного путаницы позволяет использовать это как PATRICIA trie. Джонатан отметил, что эта структура имеет почти в два раза больше информации о диапазоне по мере необходимости. После левого или правого позвоночника будут выдаваться все те же границы lo
или hi
. Поэтому он вырезал их, только включив границу, не определенную предками:
data IntMap1 a = Empty | NonEmpty { topLo :: !Int, child :: !(IntMapNE1 a) }
data IntMapNE1 a =
Tip a
| IntMapNE1 { bound :: !Int
, left :: !(IntMapNE1 a)
, right :: !(IntMapNE1 a)
Теперь каждый node имеет либо левую границу, либо правую границу, но не обе. Правильный ребенок будет иметь только левую границу, а левый ребенок будет иметь только правую границу.
Джонатан делает еще одно изменение, перемещая значения из листьев и во внутренние узлы, что ставит их точно там, где они определены. Он также использует типы phantom для отслеживания слева и справа. Конечный тип (пока, во всяком случае)
data L
data R
newtype IntMap a = IntMap (IntMap_ L a) deriving (Eq)
data IntMap_ t a = NonEmpty !Int a !(Node t a) | Empty deriving (Eq)
data Node t a = Bin !Int a !(Node L a) !(Node R a) | Tip deriving (Eq, Show)
Некоторые аспекты этой новой реализации довольно привлекательны. Самое главное, что многие из наиболее часто используемых операций значительно быстрее. Менее важно, но очень приятно, что бит возиться гораздо легче понять.
Однако есть одна серьезная больная точка: передача отсутствующей информации диапазона вниз через дерево. Это не так уж плохо для поиска, вставки и т.д., Но в коде объединения и пересечения довольно грустно. Есть ли абстракция, которая позволила бы это сделать автоматически?
Пара крайне неопределенных мыслей:
-
Могут ли типы phantom использоваться с пользовательским классом для непосредственного привязки к рутинности?
-
Природа "пропавших кусков" несколько напоминает некоторые ситуации на молнии. Может ли быть способ использовать идеи из этой сферы?
Я начал думать об использовании промежуточного типа некоторого вида, чтобы обеспечить симметричный "вид" структуры, но я немного застрял. Я могу довольно легко конвертировать назад и вперед между базовой структурой и причудливой, но это преобразование является рекурсивным. Мне нужен способ конвертировать только частично, но я не знаю почти достаточно о фантастически построенных типах, чтобы сделать это.