Abusing list notations and GADTs to keep track of length and ensure exhaustive matching: module M = struct type ('a, 'b) t = [] : (_, unit) t | (::) : 'a * ('a, 'b) t -> ('a, unit * 'b) t end;; let rec to_list : type a b. (a, b) M.t -> a list = function | M.[] -> [] | M.(x :: xs) -> x :: to_list xs;; let decompose x = (to_list x, x);; # let all_items, M.[item1; item2] = decompose M.["hello"; "world"];; val all_items : string list = ["hello"; "world"] val item1 : string = "hello" val item2 : string = "world" On Fri, Aug 9, 2019 at 4:27 PM Richard W.M. Jones wrote: > Let's imagine you have a list of named things, but you also want to > collect them up into a single list. For example: > > let item1 = "hello" > let item2 = "world" > let all_items = [ item1; item2 ] > > let () = > printf "item1 = %s\n" item1; > printf "all_items = %s\n" (String.concat ", " all_items) > > This is fine, but there's a danger that a programmer could add item3 > but forget to add it to the "all_items" list. (In the real world > problem to which this applies, my items are complex and lengthy > structures, and the "all-things-list" is well off the bottom of the > page when you're viewing the top item). > > My idea to fix this was to write: > > let all_items = [ > ("hello" as item1); > ("world" as item2); > ] > > Actually I was slightly surprised to find this doesn't compile. I > guess because "as" can only be used like this in patterns, not > expressions. Also the scoping is wrong because the "as item1" if it > worked probably wouldn't apply outside the list. > > I haven't worked out if it's possible to write this in ordinary OCaml, > although I suppose ppx could solve it. Any ideas if this is possible? > > Rich. >