type json = Yojson.t type 'a display_format = | Human_readable : string display_format | Dev : string display_format | Json : json display_format type ex_display_format = Ex_display_format : 'a display_format -> ex_display_format let human_readable = Ex_display_format Human_readable let dev = Ex_display_format Dev let json = Ex_display_format Json type 'a pp = display_format:(string display_format) -> Format.formatter -> 'a -> unit type 'a format = { pp : 'a pp ; to_json : 'a -> json ; } type 'a with_format = { value : 'a ; format : 'a format ; } type displayable = Displayable : 'a with_format -> displayable let convert : type output . display_format:(output display_format) -> displayable -> output = fun ~display_format (Displayable { value ; format }) -> match display_format with | Json -> format.to_json value | Dev -> Format.asprintf "%a" (format.pp ~display_format) value | Human_readable -> Format.asprintf "%a" (format.pp ~display_format) value let to_json : displayable -> json = convert ~display_format:Json let bind_format : 'value format -> 'error format -> ('value,'error) result format = fun value_format error_format -> let pp ~display_format f a = match a with | Error e -> error_format.pp ~display_format f e | Ok v -> value_format.pp ~display_format f v in let to_json a = match a with | Error e -> error_format.to_json e | Ok v -> value_format.to_json v in { pp ; to_json }