Я пытаюсь построить ленивую структуру данных, которая содержит бесконечное растровое изображение. Я хотел бы поддержать следующие операции:
-
true :: InfBitMap
Возвращает бесконечное битовое изображение True, то есть все позиции должны иметь значение True.
-
falsify :: InfBitMap -> [Int] -> InfBitMap
Установите для всех позиций в списке значение False. Список возможен бесконечно. Например, falsify true [0,2..] вернет список, в котором все (и только) нечетные позиции имеют значение True.
-
check :: InfBitMap -> Int -> Bool
Проверьте значение индекса.
Вот что я мог сделать до сих пор.
-- InfBitMap will look like [(@), (@, @), (@, @, @, @)..]
type InfBitMap = [Seq Bool]
true :: InfBitMap
true = iterate (\x -> x >< x) $ singleton True
-- O(L * log N) where N is the biggest index in the list checked for later
-- and L is the length of the index list. It is assumed that the list is
-- sorted and unique.
falsify :: InfBitMap -> [Int] -> InfBitMap
falsify ls is = map (falsify' is) ls
where
-- Update each sequence with all indices within its length
-- Basically composes a list of (update pos False) for all positions
-- within the length of the sequence and then applies it.
falsify' is l = foldl' (.) id
(map ((flip update) False)
(takeWhile (< length l) is))
$ l
-- O(log N) where N is the index.
check :: InfBitMap -> Int -> Bool
check ls i = index (fromJust $ find ((> i) . length) ls) i
Мне интересно, есть ли какая-то концепция/структура данных Haskellish, которые мне не хватает, что сделает мой код более элегантным/более эффективным (константы для меня не имеют значения, просто порядок). Я попытался взглянуть на молнии и линзы, но они, похоже, не помогают. Я хотел бы сохранить сложность обновлений и проверить логарифмический (возможно, просто амортизированный логарифмический).
Примечание: перед тем, как кто-то его заподозрит, это не проблема домашней работы!
Обновление
Мне просто пришло в голову, что проверка может быть улучшена:
-- O(log N) where N is the index.
-- Returns "collapsed" bitmap for later more efficient checks.
check :: InfBitMap -> Int -> (Bool, InfBitMap)
check ls i = (index l i, ls')
where
ls'@(l:_) = dropWhile ((<= i) . length) ls
Что может быть превращено в Monad для чистоты кода.