Подтвердить что ты не робот

Есть ли способ уменьшить боль дальнего слежения?

В настоящее время тянуть запрос Джонатаном С. заменить реализацию 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 использоваться с пользовательским классом для непосредственного привязки к рутинности?

  • Природа "пропавших кусков" несколько напоминает некоторые ситуации на молнии. Может ли быть способ использовать идеи из этой сферы?


Я начал думать об использовании промежуточного типа некоторого вида, чтобы обеспечить симметричный "вид" структуры, но я немного застрял. Я могу довольно легко конвертировать назад и вперед между базовой структурой и причудливой, но это преобразование является рекурсивным. Мне нужен способ конвертировать только частично, но я не знаю почти достаточно о фантастически построенных типах, чтобы сделать это.

4b9b3361

Ответ 1

Есть ли абстракция, которая позволила бы это сделать автоматически?

Вы должны иметь возможность определить набор синонимов шаблонов, которые вам дадут. Начните со второго-последнего варианта вашего кода, т.е.:

data IntMap1 a = Empty | NonEmpty { topLo :: !Int, child :: !(IntMapNE1 a) }
data IntMapNE1 a =
    Tip a
  | IntMapNE1 { bound :: !Int
              , left :: !(IntMapNE1 a)
              , right :: !(IntMapNE1 a)

Мы вводим такое значение с привязкой от родителя в Either (указываем, является ли это низкой или высокой границей).

viewLoHi (Left lo, IntMapNE1 hi left right)
    = Just (lo, hi, (Left lo, left), (Right hi, right)
viewLoHi (Right hi, IntMapNE1 lo left right)
    = Just (lo, hi, (Left lo, left), (Right hi, right)
viewLoHi _
    = Nothing

pattern Bin' lo hi left right <- (viewLoHi -> Just (lo, hi, left, right))

Тип данных верхнего уровня отличается, поэтому ему нужен собственный синоним шаблонов

viewLoHi' (NonEmpty lo child) = viewLoHi (Left lo, child)
viewLoHi' Empty = Nothing

pattern NonEmpty' lo hi left right <- (viewLoHi' -> Just (lo, hi, left, right)

Используя только NonEmpty' и Bin', когда вы пересекаете дерево, бухгалтерия теперь должна быть полностью скрыта. (Код не проверен, поэтому здесь будут опечатки)