Support mutually-recursive groups of size greater than 2
craigfe opened this issue · comments
We currently have mu2
to support pairs of mutually recursive types, but no real way to handle the general case. A simple solution might be to just add combinators for a few more group sizes:
val mu3 : ('a t -> 'b t -> 'c t -> ('a t * 'b t * 'c t as 'res)) -> 'res
val mu4 : ('a t -> 'b t -> 'c t -> 'd t -> ('a t * 'b t * 'c t * 'd t as 'res)) -> 'res
(* etc. *)
... or perhaps there is a generic solution via Oleg.
Actually from my experiments mu2
supports more than pairs of mutually recursive types, it supports all possible recursive types as long as you can build them all from 2 of them.
Example:
type a2 = { fa1 : b2 option; fa2 : c2 option }
and b2 = { fb1 : c2 option; fb2 : d2 option }
and c2 = { fc1 : a2 option; fc2 : d2 option }
and d2 = { fd1 : a2 option; fd2 : b2 option; fd3 : c2 option }
open Irmin.Type
let mka2_t b2_t c2_t =
record "a2" (fun fa1 fa2 -> { fa1; fa2 })
|+ field "fa1" (option b2_t) (fun t -> t.fa1)
|+ field "fa2" (option c2_t) (fun t -> t.fa2)
|> sealr
let mkb2_t c2_t d2_t =
record "b2" (fun fb1 fb2 -> { fb1; fb2 })
|+ field "fb1" (option c2_t) (fun t -> t.fb1)
|+ field "fb2" (option d2_t) (fun t -> t.fb2)
|> sealr
let mkc2_t a2_t d2_t =
record "c2" (fun fc1 fc2 -> { fc1; fc2 })
|+ field "fc1" (option a2_t) (fun t -> t.fc1)
|+ field "fc2" (option d2_t) (fun t -> t.fc2)
|> sealr
let mkd2_t a2_t b2_t c2_t =
record "d2" (fun fd1 fd2 fd3 -> { fd1; fd2; fd3 })
|+ field "fd1" (option a2_t) (fun t -> t.fd1)
|+ field "fd2" (option b2_t) (fun t -> t.fd2)
|+ field "fd3" (option c2_t) (fun t -> t.fd3)
|> sealr
let b2_t, c2_t =
mu2 (fun b2 c2 ->
let a2 = mka2_t b2 c2 in
let d2 = mkd2_t a2 b2 c2 in
let c2 = mkc2_t a2 d2 in
let b2 = mkb2_t c2 d2 in
(b2, c2))
let a2_t = mka2_t b2_t c2_t
let d2_t = mkd2_t a2_t b2_t c2_t
let () =
let a = { fa1 = None; fa2 = None } in
let b = { fb1 = None; fb2 = None } in
let c = { fc1 = None; fc2 = None } in
let d = { fd1 = Some a; fd2 = Some b; fd3 = Some c } in
Format.eprintf "%a@." Repr.(pp d2_t) d
Results in
{"fd1":{},"fd2":{},"fd3":{}}
Maybe we could improve the doc by showing that this is a possibility actually
Indeed, the actual limitations of mu2
are somewhat hard to capture (which is why there's been a TODO
in its documentation for a long time). FWIW, I think the actual constraint on groups is something like "the directed graph of type co-dependencies can't contain any complete subgraphs of size greater than 2.".
I agree with the formalised constraint :-)