ocaml-ppx / ppx_deriving Goto Github PK
View Code? Open in Web Editor NEWType-driven code generation for OCaml
License: MIT License
Type-driven code generation for OCaml
License: MIT License
Incompatibiliy between Ppx_deriving_runtime.string and string when installing nanomq
#=== ERROR while installing nanomsg.1.0 =======================================#
# opam-version 1.2.2
# os linux
# command ocaml pkg/build.ml native=true native-dynlink=true lwt=true ounit=true
# path /home/sapristi/.opam/system/build/nanomsg.1.0
# compiler system (4.02.3)
# exit-code 10
# env-file /home/sapristi/.opam/system/build/nanomsg.1.0/nanomsg-13706-ad8886.env
# stdout-file /home/sapristi/.opam/system/build/nanomsg.1.0/nanomsg-13706-ad8886.out
# stderr-file /home/sapristi/.opam/system/build/nanomsg.1.0/nanomsg-13706-ad8886.err
### stdout ###
# [...]
# ocamlfind ocamlc -c -g -bin-annot -safe-string -package containers.bigarray -package ipaddr -package containers -package lwt.unix -package lwt.ppx -package ctypes -package ppx_deriving.std -I lib -I lib_test -o lib/nanomsg_lwt.cmi lib/nanomsg_lwt.mli
# ocamlfind ocamlc -c -g -bin-annot -safe-string -package containers.bigarray -package ctypes.foreign -package ipaddr -package containers -package lwt.unix -package lwt.ppx -package oUnit -I lib_test -I lib -o lib_test/suite.cmo lib_test/suite.ml
# + ocamlfind ocamlc -c -g -bin-annot -safe-string -package containers.bigarray -package ctypes.foreign -package ipaddr -package containers -package lwt.unix -package lwt.ppx -package oUnit -I lib_test -I lib -o lib_test/suite.cmo lib_test/suite.ml
# File "lib_test/suite.ml", line 29, characters 13-40:
# Error: This expression has type
# Nanomsg.Addr.connect Nanomsg.Addr.t -> Ppx_deriving_runtime.string
# but an expression was expected of type
# Nanomsg.Addr.connect Nanomsg.Addr.t -> string
# Type Ppx_deriving_runtime.string is not compatible with type string
# Command exited with code 2.```
for example:
type point = { x: float ; y: float } [@@deriving create]
val create : x:float -> y:float -> unit -> point
I thought the unit
is only necessary if any of the labels have a default value? (i.e. optional).
Although the README.md
suggests that one should read through the included plugins in order to learn how to develop a new one, the included plugins are somewhat lacking in documentation (from what I can tell), which may be raising the entry barrier for plugin development. I would submit a PR with some in-code comments, but I'm not entirely certain that I understand ppx_deriving
well enough to do this. Would it be possible to come up with more user-friendly plugin development information?
It would be nice to be able to write:
type t = {
id : int;
meta : string [@ord.ignore] [@show.elide];
} [@@deriving ord, show]
to support something similar to:
assert (equal { id = 1; meta = "foo" } { id = 1; meta = "bar" });
assert ("{ id = 1; meta = ... }" = show { id = 1; meta = "elide me" });
When you try to derive for a type like:
type foo = F of int | B of int bar | C of float bar
type 'a bar = { x : 'a ; r : Foo }
You will end up with recursive functions:
let rec pp_foo ...
and pp_bar poly_a ...
However, the recursive binding does not allow for multiple instantiations of the polymorphic argument. Hence, you should probably move that out of the recursive group.
I'm playing around with @camlspotter's TyPPX library. With a ppx preprocessor that depends on TyPPX (an identity mapper is sufficient to reproduce this) and ppx_deriving in the same project, I get show cannot be derived for int
for records:
type a = { b : int }
[@@deriving show]
Strangely, this
type c = int
[@@deriving show]
compiles and works fine.
Right now, only constructors with one argument have parenthesis around them. Omitting parenthesis is ok for nullary constructors, but shouldn't be for n-ary ones (as the the output can no longer simply be pasted into the top-level):
type t = A | B of t | C of t*t [@@deriving show];;
show @@ A;; (* A *)
show @@ B A;; (* (B A) *)
show @@ C (A, A);; (* C (A, A) but should be (C (A, A)) *)
show @@ B (C (A, A));; (* (B C (A, A)) <- problem *)
I use deriving show just to make it easier to see stuff in utop, but when I compile the code, it doesn't seem to get applied unless I refer to the show function somewhere in the code. Perhaps the README should mention this, since it may be a bit confusing to newcomers.
/cc @diml
Not sure how this would actually work, but it would be nice to have at least a pretty printer for object via ppx_deriving.
When doing print_string (show_qsqdsqd dqsd)
, merlin says Error: This expression has type Ppx_deriving_runtime.string but an expression was expected of type string
, although the code compiles and runs well.
This is to keep ppx_deriving similar to type_conv.
/cc @diml
In a similar way to variantslib and fieldslib, be able to generate functions:
type foo =
| A of int
| B of string * foo
[@@deriving variants];;
(* generated *)
val a : int -> foo
val b : string -> foo -> foo
and
type space_point = {
x : int;
y : int;
history : space_point list;
} [@@deriving fields];;
(* generated *)
val x : space_point -> int
val y : space_point -> int
val history : space_point -> space_point list
utop # type t = [ `A ] [@@deriving eq];;
Characters 0-31:
Warning 11: this match case is unused.
type t = [ `A ]
val equal : t -> t -> bool = <fun>
(It does not happen with yojson
, or show
)
Consider the following code (printer_variant.ml):
type t =
| First [@printer fun fmt _ -> Format.fprintf fmt "first case"]
| Second
[@@deriving show]
let () =
Format.printf "%a, %a@." pp First pp Second
Extrapolating from the documentation, I expect the output to be "first case, Printer_variant.Second". But:
$ ./printer_variant
Printer_variant.First, Printer_variant.Second
Would it be possible to support adding [@printer] attributes to the cases of a variant type, so that the behavior matches my expectations?
The Big_int type from the standard library is a little bit "awkward", it doesn't fit in the standard convention. Would it be possible to have special cases to support this special case?
As a wishlist entry.
Currently:
# type _ s = B : int -> int s | C : float -> float s [@@deriving Show];;
Error: This pattern matches values of type float s
but a pattern was expected which matches values of type int s
Type float is not compatible with type int
# type x = int array [@@deriving eq] ;;
type x = int array
val equal_x : x -> x -> bool = <fun>
# equal_x [| |] [| |] ;;
Exception: Invalid_argument "index out of bounds".
Will PR a fix.
The generated code uses List.map
and expects a particular order for its arguments which is not the one used in Core_kernel
or nonstd.
#require "ppx_deriving.show";;
type t = {x: string list} [@@deriving show];;
(*
type t = { x : bytes list; }
val pp : Format.formatter -> t -> unit = <fun>
val show : t -> bytes = <fun>
*)
module List = struct
include ListLabels
let map l ~f = map ~f l
end
type t = {x: string list} [@@deriving show];;
(*
Error: This expression should not be a function, the expected type is
'a list
*)
I recommend generating code that uses ListLabels.map
directly, it's much less likely that anyone will override that name, and using labels will make much better error messages anyway.
Edit: comments, formatting and typos
This may be an exercise in bikeshedding, but naming constructors make
seems to be a more common practice. Is there a particular reason why ppx_deriving chose create
?
That would be cool maybe (just thinking out “loud”):
type cmd1 = {arg1: string option; arg2: int} [@@deriving command_line]
type cmd2 =
{arg1: string [@short_name "a" ];
arg2: int option;
arg3: more_complex [@of_string some_fun]
anonymous: string list}
[@@deriving command_line]
type super_command = [
| `cmd1 of cmd1
| `cmd2 of cmd2
]
[@@deriving command_line]
type global_options = {foo: string option; bar: [`A | `B | `C] option}
[@@deriving command_line]
type t = (global_options * super_command)
[@@deriving command_line {master = true}]
and would generate a parse-command-line function:
val parse_t: ?argv:string array -> unit -> t
(or just a t CmdLiner.Term.t
?)
Now that automatic dynlinking is gone, it's very easy to check whether a deriver exists or not.
/cc @diml
Could you detail how to build ppx_deriving without OPAM for ppl with OCaml on MinGW?
From opam
file, it seems to be
$ sed -e 's/%{version}%/1.1/g' pkg/META.in > pkg/META
$ ocaml pkg/build.ml native=true native-dynlink=true
In my environment the above builds things fine. The hard part is the installation. I had to run ocamlifind
manually getting the file information from ppx_deriving.install
.
Thanks!
Citing your blog post http://whitequark.org/blog/2014/04/16/a-guide-to-extension-points-in-ocaml/ it should be something like this:
$ ocamlfind ppx_tools/rewriter ./ppx_deriving_main.native test.ml
But I'm not sure where to pass the names of concrete plugins. For example ppx_deriving.eq
utop # type tt = Machin | Chose [@printer fun fmt -> fprintf fmt "chose"] [@@deriving Show];
;
type tt = Machin | Chose
val pp_tt : Format.formatter -> tt -> unit = <fun>
val show_tt : tt -> bytes = <fun>
utop # show_tt Chose;;
- : bytes = "Chose"
Is there a way to generate printers for recursive types?
For example,
type 'a exp = [
| `Plus of 'a * 'a
| `Num of int
] [@@deriving show]
let rec eval = function
| `Plus (e1, e2) -> eval e1 + eval e2
| `Num i -> i
;;
let ast = (`Plus (`Plus (`Num 1, `Num 2), `Plus (`Num 3, `Num 4))) in
let result = eval ast in
print_endline @@ show_magic @@ ast;
print_endline @@ string_of_int @@ result;
I'm guessing the printer would look something like eval
, but would compose a given pp
function. Don't understand ppx_deriving
well enough to know how difficult this is though.
In ppx_deriving 2.2., it was possible to apply @@deriving on a module that happens to have the same name as a standard library module, e.g.:
module List = struct
type 'a t = [`Cons of 'a | `Nil] [@@deriving show]
end
type 'a t = 'a List.t option [@@deriving show]
However, this results in an error in ppx_deriving 3.0:
ocamlfind ocamlc -c -package 'ppx_deriving.std' test.ml
File "test.ml", line 4, characters 0-46:
Error: Unbound value List.pp
Looking at the output of ppx_tools/rewriter
, it appears that Ppx_deriving_runtime.List is shadowing the user-defined List module:
module List = struct ... end
let rec pp : ... =
((let open! Ppx_deriving_runtime in
fun poly_a ->
fun fmt ->
function
| None -> Format.pp_print_string fmt "None"
| Some x ->
(Format.pp_print_string fmt "(Some ";
(List.pp (fun fmt -> poly_a fmt) fmt) x;
Format.pp_print_string fmt ")"))[@ocaml.warning "-A"])
and ...
The opam package for 2.1 should probably be constrained to OCaml >= 4.02.2
Looks like attributes are ignored in 4.02.2:
#require "ppx_deriving.show";;
type foo = { bar : int [@opaque] } ;;
show_foo {bar=1};;
expect: { bar = <opaque>"}
got: { bar = 1 }
I would like to be able to derive visitors, in the style of Ast_mapper
.
Given a set of type in a type ... and ...
declaration, a visitor would be a record with one field per type and a field for each external type used in the type declarations.
I can't build the latest of ppx_deriving and ppx_protobuf.
$ opam pin -k git add ppx_deriving_protobuf ppx_deriving_protobuf
[NOTE] Package ppx_deriving_protobuf is already pinned to /home/cpiccion/workspace/ppx_deriving_protobuf. This will reset metadata.
Proceed ? [Y/n] y
[ppx_deriving_protobuf] Fetching /home/cpiccion/workspace/ppx_deriving_protobuf
Installing new package description for ppx_deriving_protobuf from /home/cpiccion/workspace/ppx_deriving_protobuf/opam
ppx_deriving_protobuf needs to be installed.
The following dependencies couldn't be met:
No solution found, exiting
[NOTE] Pinning command successful, but your installed packages may be out of sync.
However, I have ppx_deriving pinned to .3 via github:
$ opam pin list
ppx_deriving.0.3 git /home/cpiccion/workspace/ppx_deriving
ppx_deriving_protobuf.1.0.0 git /home/cpiccion/workspace/ppx_deriving_protobuf
The package descriptor for the new make
plug-in is missing (should be in pkg/META.in). This causes the following error when ppx_deriving.std is referenced:
ocamlfind: Package
ppx_deriving.make' not found - required by
ppx_deriving.std'
Pull request incoming.
I have found ord and eq very useful, specially with the capability of providing custom functions. In the same fashion it would be great having a deriving hash to be used with Hashtbl.Make.
utop # module rec Foo : sig type ('a,'b) t = ('b, 'a) Bar.t end =
struct type ('a,'b) t = ('b,'a) Bar.t end
and Bar : sig type ('b, 'a) t = 'b * 'a end = struct type ('b,'a) t = 'b * 'a end;;
module rec Foo : sig type ('a, 'b) t = ('b, 'a) Bar.t end and Bar : sig type ('b, 'a) t = 'b * 'a end
utop # module rec Foo : sig type ('a,'b) t = ('b, 'a) Bar.t [@@deriving show] end =
struct type ('a,'b) t = ('b,'a) Bar.t [@@deriving show] end
and Bar : sig type ('b, 'a) t = 'b * 'a [@@deriving show] end =
struct type ('b,'a) t = 'b * 'a [@@deriving show] end;;
Error: Signature mismatch: ... Values do not match:
val pp :
(Format.formatter -> 'a -> unit) ->
(Format.formatter -> 'b -> unit) ->
Format.formatter -> ('b, 'a) Bar.t -> unit
is not included in
val pp :
(Format.formatter -> 'b -> unit) ->
(Format.formatter -> 'a -> unit) ->
Format.formatter -> ('a, 'b) t -> unit
no possibility to derive Show with
type foo = int -> int ( for example ) ?
spasibo
I have some trouble understanding what looks like an issue with the ppx_deriving ocamlfind package.
ocamlfind ocamldep -package X ... -package Z -modules myfile.mli
outputs a proper list of depencides, e.g.,
myfile.mli: Format Hex Z
while
ocamlfind ocamldep -package X ... -package Z -package ppx_deriving -modules myfile.mli
produces an empty dependency list for myfile.mli
.
Would you have any idea about what's going on?
Basically, this is the use case: https://github.com/Drup/Syndic/blob/0e494be62e673888cb2245db29b62129206bf25f/lib/syndic_atom.ml#L1053-L1059
Features:
options
, lists
, [@default <bla>]
, ...) are in an optional argument[@main]
?) is without label, the rest are with labels. If there is no main field, the function ends by ()
.~hd
+ ?tl
for foo * foo list
(list with at least one element)).I don't see anything else right now.
For example:
type t = {
foo : Foo.t option
} [@@deriving show]
The generated identifier Foo.to_string
could be located either to the foo
field or to the Foo.t
type.
It would help with big records (No, I didn't wrote this monstrosity).
I think there should be a way to apply the deriving-mapper to expression-valued attributes. Maybe as an alternative Arg.expr or by exposing the mapper as a global?
My motivation is that I wrote a syntax extension to generate random instances of types. The derived-from type takes an attribute [@random ...]
to override with custom generator code, where I need reliable way to refer to generators for parameters or the type itself, e.g. in
type 'a term =
| Var of 'a
| App [@weight 0.5] of 'a term * 'a term
| Lam of ('a * 'a term) [@random random_lambda [%random: 'a term]]
[@@deriving random]
In other cases random_lambda
might use just [%random: 'a]
. The internal name poly_a
is needed in either case, which makes me think the best way to refer to it is to use [%random: ...]
. I could systematically apply all parameter generators to the custom generator and use:
| Lam of ('a * 'a term) [@random random_lambda random_term]
In my opinion, explicit arguments are nicer.
The sensible handling would be to test if it's evaluated (with Lazy.is_val) and print it or <not evaluated>
.
If I use [%derive.show: statement list]
and that statement
is not found, the error is the following:
File "_none_", line 1:
Error: Unbound value pp_statement
With MinGW OCaml, the build command ocaml pkg/build.ml native=true native-dynlink=true
fails as follows:
Solver failed:
Ocamlbuild knows of no rules that apply to a target named src/ppx_deriving.lib. This can happen if you ask Ocamlbuild to build a target with the wrong extension (e.g. .opt instead of .native) or if the source files live in directories that have not been specified as include directories.
Backtrace:
- Failed to build the target src/ppx_deriving.lib
- Building src/ppx_deriving.lib
I guess this is since MinGW OCaml uses a cross compiler for MinGW which produces library files with *.a
instead of *.lib
. The following quick but not entirely correct patch againnst topkg.ml
fixed the issue:
--- a/pkg/topkg.ml
+++ b/pkg/topkg.ml
@@ -152,7 +152,7 @@ end
module Exts : Exts = struct
let interface = [".mli"; ".cmi"; ".cmti"]
let interface_opt = ".cmx" :: interface
- let c_library = if Sys.win32 then [".lib"] else [".a"]
+ let c_library = [".a"]
let c_dll_library = if Sys.win32 then [".dll"] else [".so"]
let library = [".cma"; ".cmxa"; ".cmxs"] @ c_library
let module_library = (interface_opt @ library)
To fix the issue properly, I guess you need to find which C compiler OCaml actually executes.
Simple example:
type foo = { x:int [@compare (fun i j -> 0)] } [@@deriving ord];;
compare_foo {x=1} {x=2};; (* ok, returns 0 *)
type foo = { x:int [@ord.compare (fun i j -> 0)] } [@@deriving ord];;
compare_foo {x=1} {x=2};; (* not ok, returns -1, should return 0? *)
Sometimes it's convenient to serialize a polymorphic variant using it's hash value. Unfortunately Btype.hash_variant
is not accessible from a ppx_deriving
plugin. And I cannot dynload ocamlcommon.cma
because it uses unsafe features. Do you know the way to calculate hash value without copy&paste from btype.ml
?
I recommend adding version: "dev"
to the opam
file. Currently, if you pin, opam still reports the version as 0.3, which is slightly unintuitive. Adding this line will cause the version to be called "dev".
misclick oops
I don't know if it is linked with #42 but since 2.1 ppx_deriving doesn't work inside merlin anymore (work with ocamlfind directly).
It seems to be linked with the renaming of the command since the following hack fix the problem, after installation:
ppx = "./ppx_deriving_main"
by ppx = "./ppx_deriving"
ppx_deriving_main
to ppx_deriving
Perhaps the bug is in merlin.
There's no need for the
[`Ok of 'a | `Error of string]
polymorphic variant as result
is available in 4.03 and as a findlib packages for earlier OCaml's.
Is there anyway to make this transition without breaking a bunch of code?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.