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.
Following this thread, I tried to have this piece of code working but I am stuck into this compilation error. I feel the [@@deriving yojson] is not working as expected, but I canāt manage to solve it.:
File "bin/main.ml", lines 29-32, characters 25-3:
29 | .........................struct
30 | type t = int [@@deriving yojson]
31 | let compare = Stdlib.compare
32 | end
Error: Signature mismatch:
...
The value t_of_yojson is required but not provided
File "bin/main.ml", line 7, characters 2-38: Expected declaration
The value yojson_of_t is required but not provided
File "bin/main.ml", line 8, characters 2-38: Expected declaration
open Ppx_yojson_conv_lib.Yojson_conv.Primitives
open Ppx_yojson_conv_lib.Yojson_conv
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 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) =
let conv = pair_of_yojson O.t_of_yojson (fun x -> x)in
of_list (list_of_yojson conv json)
let yojson_of_t (t:'a t) =
yojson_of_list (yojson_of_pair O.yojson_of_t (fun x->x)) (to_list t)
end
end
module Int:OrderedType = struct
type t = int [@@deriving yojson]
let compare = Stdlib.compare
end
module IntMap = Map.Make(MyInt)
That doesnāt look like the code that you compiled above? There are no ā@@derivingā attributes in it? Can you share a complete example? E.g., maybe put it up on GitHub and share a link ?
Typically when I get into these sorts of problems, I will look in the ālogā file in the Dune build directory and find the compile directives that cause the problem, and add ā-dsourceā to get the source code post-PPX, and then I can try to compile that and debug my way to understanding what went wrong.
Itās been a really long time, but maybe the problem is that when the type is ātā, you donāt get āt_of_yojsonā, but instead āof_yojsonā. Iām just guessing ā my laptop is in a bit of a shambles, so I canāt run emacs well enough to tool around in sources to check. But you can verify that by using ā-dsourceā.
You are a good guesser ! I have checked and thatās indeed what I have seen⦠plus it looks like to_yojson and of_yojson are recursive functions⦠ā-dsourceā helped a lot for that. Thank you, I am now digging further.
Note that you can do dune describe pp path/to/file.ml to get the preprocessed version of the file without having the dig in the logs.
From what you are saying now it sounds like you have switched from ppx_yojson_conv to ppx_deriving_yojson at some point during development. The names of the functions they generate are different. If you want to work with the Janestreet ecosystem you should probably use ppx_yojson_conv.
Thank you @Khady for the tip on dune : dune describe pp path/to/file.ml I will try that as well. -dsource worked without digging into the logs (printed on the output, but maybe just because it was not compilingā¦)
Good hint as well about ppx_yojson_conv versus ppx_deriving_yojson. I must confess that I wasnāt really aware of those two flavors of the same lib, hence neither of a mix in my code. Thatās what happens when you learn things alone. You get information from various sources but never get the whole picture you would get from an expert/teacher⦠That will help too !