Hey, I wonder how one can get it working with a Map. For example,
module M = Map.Make(Int)[@@deriving of_yojson]
let m = M.empty |> M.add 1 2 |> M.add 3 4 |> M.add 5 6
let s =
[%yojson_of: int M.t] m
|> Yojson.Safe.to_string;;
module M = struct
module Tmp = Map.Make(Int)
include Tmp
let yojson_of_t m = Tmp.bindings m |> [%yojson_of: (int * int) list]
end
let m = M.empty |> M.add 1 2 |> M.add 3 4 |> M.add 5 6
let s =
[%yojson_of: M.t] m
|> Yojson.Safe.to_string
You can do that, or you can expand the module at the functor level to keep its versatility. Example of expanding Set:
module Set = struct
module type S = sig
include Set.S
val t_of_yojson : Yojson.Safe.t -> t
val yojson_of_t : t -> Yojson.Safe.t
end
module Make(O:OrderedType) = struct
include Set.Make(O)
let t_of_yojson (json:Yojson.Safe.t) =
list_of_yojson O.t_of_yojson json |> of_list
let yojson_of_t (t:t) =
to_list t |> yojson_of_list O.yojson_of_t
end
end
module M = struct
module Tmp = Map.Make(Int)
include Tmp
let yojson_of_t m = Tmp.bindings m |> [%yojson_of: (int * int) list]
end
let m =
M.empty
|> M.add 1 2
|> M.add 3 4
|> M.add 5 6
let s =
m
|> [%yojson_of: M.t]
|> Yojson.Safe.to_string
module Nested = struct
module Tmp = Map.Make(Int)
include Tmp
let yojson_of_t m = Tmp.bindings m |> [%yojson_of: (int * M.t) list]
end
let m =
M.empty
|> M.add 1 2
|> M.add 3 4
|> M.add 5 6
let s =
Nested.empty
|> Nested.add 1 m
|> Nested.add 2 m
|> [%yojson_of: Nested.t]
|> Yojson.Safe.to_string
(* expand at Functor level *)
module type OrderedType = sig
type t
val compare : t -> t -> int
val t_of_yojson : Yojson.Safe.t -> t
val yojson_of_t : t -> Yojson.Safe.t
end
module Set = struct
module type S = sig
include Set.S
val t_of_yojson : Yojson.Safe.t -> t
val yojson_of_t : t -> Yojson.Safe.t
end
module Make(O:OrderedType) = struct
include Set.Make(O)
let t_of_yojson (json:Yojson.Safe.t) =
list_of_yojson O.t_of_yojson json |> of_list
let yojson_of_t (t:t) =
to_seq t |> List.of_seq |> yojson_of_list O.yojson_of_t
end
end
module Int = struct
type t = int [@@deriving yojson]
let compare = Stdlib.compare
end
module M = Set.Make(Int)
let s =
M.empty
|> M.add 1
|> M.add 2
|> M.add 3
|> [%yojson_of: M.t]
|> Yojson.Safe.to_string
This feels hacky, but for a one-off [%yojson_of] use you just need the right functions with the right names in scope, not even the types:
let yojson_of_int_map yojson_of_value map =
let module M = Map.Make (Int) in
[%yojson_of: (int * value) list] (M.bindings map)
let int_map_to_string yojson_of_value map =
Yojson.Safe.to_string ([%yojson_of: value int_map] map)
The types value and 'a int_map don’t actually exist here, but the PPX produces the right calls to yojson_of_value and yojson_of_int_map yojson_of_value anyway.
However, using an actual alias type 'a int_map = 'a Map.Make (Int).t would also enable other types to use [@@deriving yojson_of] without redefining a full Map module. You can then hide those aliases from your module signature if you want.
I did this (just as you did) for both maps and sets, and for yojson and show. And for the latter, I wanted both pp and pp_hum. It’s a pity there’s no way to “add” these extra functions, but then, I guess once you make the new extended functors, you can use them all over the place, so it’s not like there’s a giant expenditure of effort.
Hey, Chet, can you share your implementation for a Map: I can’t figure out how to deal with the values being stored:
type t
val compare : t -> t -> int
val t_of_yojson : Yojson.Safe.t -> t
val yojson_of_t : t -> Yojson.Safe.t
end
module Map = struct
module type S = sig
include Map.S
val t_of_yojson : Yojson.Safe.t -> 'a t
val yojson_of_t : 'a t -> Yojson.Safe.t
end
module Make(O:OrderedType) = struct
include Map.Make(O)
let t_of_yojson (json:Yojson.Safe.t) =
list_of_yojson O.t_of_yojson json |> List.to_seq |> of_seq
let yojson_of_t (t:t) =
to_seq t |> List.of_seq |> yojson_of_list O.yojson_of_t
end
end;;
the error message:
Error: This expression has type key Seq.t = unit -> key Seq.node
but an expression was expected of type
(key * 'a) Seq.t = unit -> (key * 'a) Seq.node
Type key is not compatible with type key * 'a ```
N.B.: this uses my camlp5-based pa_ppx PPX rewriters, not the standard ppxlib PPX infrastructure. But these are the bog-standard ones, so the code should work with the standard rewriters. Looking at the code, I see that I didn’t implement to_yojson. I don’t remember if this is because there was a problem, or b/c I didn’t need it.
I never use utop, but also, since all of my code is based on camlp5, the mechanism whereby pretty printing in toplevels happens is probably different from how it works with the normal PPX infrastructure. generally, I use #install_printer And that has worked perfectly fine.