Я пытаюсь перечислить набор всех пар, состоящих из элементов из двух ленивых списков (первый элемент из первого списка, второй элемент из второго списка) в OCaml, используя обычную идею диагонализации. Идея, строго говоря, выглядит примерно так:
enum [0;1;2;...] [0;1;2;...] = [(0,0);(0,1);(1;0);(0;2);(1;1);(2;2);...]
У меня вопрос: как это определить «лениво»?
Я объясню, о чем думал до сих пор, может быть, это будет полезно для тех, кто пытается на это ответить. Но если вы уже знаете ответ, вам не нужно читать дальше. Я могу пойти неправильным маршрутом.
Я определил ленивые списки как
type 'a node_t =
| Nil
| Cons of 'a *'a t
and 'a t = ('a node_t) Lazy.t
Затем я определил функцию seq
let seq m =
let rec seq_ n m max acc =
if n=max+1
then acc
else (seq_ (n+1) (m-1) max (lazy (Cons((n,m),acc))))
in seq_ 0 m m (lazy Nil)
что дает мне ленивый список пар (x, y) таких, что x + y = m. В этом суть диагональной идеи. Мы начинаем с перечисления всех пар с суммой 0, затем всех пар с суммой 1, затем пар с суммой 2 и т. Д.
Затем я определил функцию enum_pair
let enum_pair () =
let rec enum_pair_ n = lazy (Cons(seq n,enum_pair_ (n+1)))
in enum_pair_ 0
который генерирует бесконечный ленивый список, состоящий из: ленивого списка пар с суммой 0, конкатенированных с ленивыми списками пар с суммой 1 и т. д.
Сейчас мне кажется, что я почти у цели. Теперь проблема заключается в следующем: как мне получить фактические пары одну за другой?
Мне кажется, что мне пришлось бы использовать некую форму конкатенации списков (ленивый эквивалент @). Но это неэффективно, потому что в моем представлении ленивых списков объединение двух списков имеет сложность O (n ^ 2), где n - размер первого списка. Стоит ли мне использовать другое представление ленивых списков? Или есть другой способ (без использования seq и enum_pair выше), который не требует конкатенации списков?
Любая помощь могла бы быть полезна.
Большое спасибо, Сурикатор.