Вы можете использовать списки добавления Джона Хьюза с постоянным временем, которые в настоящее время кажутся именуемыми DList
. Представление - это функция от списков к спискам: пустой список - это функция тождества; append - композиция, а singleton - минусы (частично применены). В этом представлении каждое перечисление будет стоить вам n
ассигнований, так что это может быть не так хорошо.
Альтернатива состоит в том, чтобы создать ту же алгебру, что и структура данных:
type 'a seq = Empty | Single of 'a | Append of 'a seq * 'a seq
Перечисление - это обход дерева, который либо будет стоить некоторого стекового пространства, либо потребует некоторого представления молния. Вот прогулка по дереву, которая преобразуется в список, но использует пространство стека:
let to_list t =
let rec walk t xs = match t with
| Empty -> xs
| Single x -> x :: xs
| Append (t1, t2) -> walk t1 (walk t2 xs) in
walk t []
Вот то же самое, но с использованием постоянного стека:
let to_list' t =
let rec walk lefts t xs = match t with
| Empty -> finish lefts xs
| Single x -> finish lefts (x :: xs)
| Append (t1, t2) -> walk (t1 :: lefts) t2 xs
and finish lefts xs = match lefts with
| [] -> xs
| t::ts -> walk ts t xs in
walk [] t []
Вы можете написать функцию свертывания, которая посещает те же элементы, но фактически не обновляет список; просто замените минусы и ноль на что-то более общее:
val fold : ('a * 'b -> 'b) -> 'b -> 'a seq -> 'b
let fold f z t =
let rec walk lefts t xs = match t with
| Empty -> finish lefts xs
| Single x -> finish lefts (f (x, xs))
| Append (t1, t2) -> walk (t1 :: lefts) t2 xs
and finish lefts xs = match lefts with
| [] -> xs
| t::ts -> walk ts t xs in
walk [] t z
Это ваше перечисление с постоянным стеком за линейное время. Веселись!