Редактировать: добавлено больше о Thunk.
Начните с просмотра только преобразования из списка различий в обычный список. Эта операция сама по себе занимает только постоянное время, потому что оценка не требуется. Результирующий список будет существовать как thunk, который будет структурирован примерно так:
Базовое определение (++)
является ассоциативным справа и должно пройти через весь первый аргумент, прежде чем он сможет продолжить со вторым аргументом. Это отлично согласуется с вложенной структурой, созданной списком различий, поскольку каждый (++)
получает один блок списка в качестве первого аргумента. Кроме того, поскольку (++)
является хорошим производителем списков, вся структура существует лениво. Хотя для полной оценки требуется O (n), оценка только головы - это O (k), где k=number of chunks
.
Рассмотрим, если a,b == []; c = [1..]
. Затем head
необходимо сначала проверить, что a
и b
пусты, прежде чем перейти к c
и найти первый элемент. В худшем случае head
обойдет всю структуру, прежде чем найдет пустой конструктор списка. Однако на практике это очень редкий случай, и даже в этом случае он не особенно вреден, поскольку обнаружение пустого куска и переход к нему - операция с постоянным временем.
В общем случае оценка списка различий должна отличаться от обычного списка сложностью времени только постоянным фактором для эквивалентных операций.
Создание только первого элемента списка разностей не требует времени O (n), что легко можно продемонстрировать с помощью бесконечных списков:
*Dl Control.Monad Control.Applicative> head $ ($ []) $ toDl [1..] . toDl [4..]
1
(0.01 secs, 2110104 bytes)
*Dl Control.Monad Control.Applicative> fmap (head . ($ [])) $ headTailDifList (toDl [1..])
(1,2)
(0.00 secs, 2111064 bytes)
*Dl Control.Monad Control.Applicative> fmap (head . ($ [])) $ headTailDifList (toDl [1..] . toDl [3..] . toDl [] . toDl [5..])
(1,2)
(0.01 secs, 3105792 bytes)
-- create a difference list
toDl :: [a] -> ([a] -> [a])
toDl l = (l ++)