-
Notifications
You must be signed in to change notification settings - Fork 159
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
irmin.type: improve pp_ty #997
Conversation
This change also fixes an existing 'bug' in which the fixpoints were unfolded once more than necessary (by returning the unfolded form). This was observable when pretty-printing the type.
This representation is not exported to users, but is useful for e.g. pretty-printing of recursive types.
Previously, pretty-printing a non-trivial use of the `mu` combinator would result in stack overflow.
Nice! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is neat! sorry for taking so long to have a look at it.
I'm wondering is there is a reason to have ([ Empty | Node of ((tree * int * tree) as 'a) ] as tree)
instead of ([ Empty | Node of node] as tree)
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good, thanks.
Can you add a changelog entry for this?
Your suggestion is certainly cleaner. I tried it, but decided against it for two reasons:
The |
Done. |
@@ -100,7 +103,7 @@ and 'a custom = { | |||
|
|||
and ('a, 'b) map = { x : 'a t; f : 'a -> 'b; g : 'b -> 'a; mwit : 'b Witness.t } | |||
|
|||
and 'a self = { mutable self : 'a t } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does embedding self_unroll
into every recursive variant or record add any noticeable overhead? If I understand correctly, this new field is required to avoid stack overflows when pretty-printing, but does it also help outside of pretty-printing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does embedding
self_unroll
into every recursive variant or record add any noticeable overhead?
I haven't measured, but I expect not. I imagine that the number of self
values in most programs would be negligible.
If I understand correctly, this new field is required to avoid stack overflows when pretty-printing, but does it also help outside of pretty-printing?
It's currently just for pretty-printing.
If we ever have other cases where we recurse over the structure of representations without a corresponding value – such as if we ever support ∀ a. a Type.t -> a Type.t Type.t
– self_unroll
will be necessary to avoid infinite recursion.
…min-mirage-graphql, irmin-http, irmin-git, irmin-mem, irmin-mirage, irmin-unix, irmin-pack, irmin-graphql and irmin-mirage-git (2.2.0) CHANGES: #### Added - **irmin**: - Added `Irmin.Type.empty` to represent an uninhabited type. (mirage/irmin#961, @craigfe) - Added `Store.Tree.concrete_t`. (mirage/irmin#1003, @craigfe) - **ppx_irmin** - Added support for the `@nobuiltin` attribute, which can be used when shadowing primitive types such as `unit`. See `README_PPX` for details. (mirage/irmin#993, @craigfe) - Added support for a `lib` argument, which can be used to supply primitive type representations from modules other than `Irmin.Type`. (mirage/irmin#994, @craigfe) #### Changed - **irmin**: - Require OCaml 4.07 (mirage/irmin#961, @craigfe) - Add sanity checks when creating `Irmin.Type` records, variants and enums (mirage/irmin#956 and mirage/irmin#966, @liautaud): - `Irmin.Type.{sealr,sealv,enum}` will now raise `Invalid_argument` if two components have the same name; - `Irmin.Type.{field,case0,case1}` will now raise `Invalid_argument` if the component name is not a valid UTF-8 string. - Changed the JSON encoding of options and unit to avoid ambiguous cases (mirage/irmin#967, @liautaud): - `()` is now encoded as `{}`; - `None` is now encoded as `null`; - `Some x` is now encoded as `{"some": x}`; - Fields of records which have value `None` are still omitted; - Fields of records which have value `Some x` are still unboxed into `x`. - Changed pretty-printing of Irmin types to more closely resemble OCaml types. e.g. `pair int string` prints as `int * string`. (mirage/irmin#997, @craigfe) - The type `Irmin.S.tree` is now abstract. The previous form can be coerced to/from the abstract representation with the new functions `Irmin.S.Tree.{v,destruct}` respectively. (mirage/irmin#990, @craigfe) - **irmin-mem** - Stores created with `KV` now expose their unit metadata type. (mirage/irmin#995, @craigfe) #### Fixed - **irmin-graphql** - Fixed an issue with keys inside `get_{contents,tree}` fields having incorrect ordering (mirage/irmin#989, @craigfe)
Resolves #958.
This changes the pretty-printer for Irmin types to more closely match OCaml types (e.g.
(unit * int) option
rather thanOption (Pair (Prim Unit, Prim Int))
). It adds functionality for pretty-printing the components of algebraic types: record types are pretty-printed like OCaml object types and variants are pretty-printed similarly to OCaml polymorphic variants.The tricky case here is recursive types, which were previously broken (would cause stack overflow when pretty-printed). Handling this properly requires preserving the
unroll
function passed to themu
combinator for later use. The type can then be pretty-printed by unrolling once with a type alias:For recursive or mutually recursive types that are not algebraic, there is no sensible name for the type alias, so we pick them in some deterministic order.
This change also fixes an existing 'bug' in which the
mu
andmu2
fixpoints were unfolded once more than necessary (by returning the unfolded form). This was observable when pretty-printing the type.