Code: (from OCaml  The module system )
module PrioQueue = struct
type priority = int
type 'a queue = Empty  Node of priority * 'a * 'a queue * 'a queue
let empty = Empty
let rec insert queue prio elt =
match queue with
 Empty > Node (prio, elt, Empty, Empty)
 Node (p, e, left, right) >
if prio <= p then Node (prio, elt, insert right p e, left) else Node (p, e, insert right prio elt, left)
exception Queue_is_empty
let rec remove_top = function
 Empty > raise Queue_is_empty
 Node (_prio, _elt, left, Empty) > left
 Node (_prio, _elt, Empty, right) > right
 Node (_prio, _elt, (Node (lprio, lelt, _, _) as left), (Node (rprio, relt, _, _) as right)) >
if lprio <= rprio then Node (lprio, lelt, remove_top left, right)
else Node (rprio, relt, left, remove_top right)
let extract = function
 Empty > raise Queue_is_empty
 Node (prio, elt, _, _) as queue > (prio, elt, remove_top queue)
end
module PrioQueueOpt = struct
include PrioQueue
let remove_top_ot x = try Some (remove_top x) with Queue_is_empty > None
let extract_opt x = try Some (extract x) with Queue_is_empty > None
end
This code compiles regardless of whether I use include PrioQueue
or open PrioQueue
.
My current (possibly incorrect) understanding is:

open
adds bindings to local env referencing openeed module 
include
literally copies over the code
I regularly use open
. I have seen code with include
, but I don’t think
I have ever used it myself.
What are situations where open
is not sufficient and we have to use include
?