Skip to content
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

Support GADTs in or-patterns #5736

Closed
vicuna opened this issue Aug 22, 2012 · 9 comments
Closed

Support GADTs in or-patterns #5736

vicuna opened this issue Aug 22, 2012 · 9 comments
Assignees
Labels
feature-wish typing typing-GADTS GADT typing and exhaustiveness bugs

Comments

@vicuna
Copy link

vicuna commented Aug 22, 2012

Original bug ID: 5736
Reporter: omion
Assigned to: @garrigue
Status: confirmed (set by @garrigue on 2012-08-22T23:27:03Z)
Resolution: open
Priority: normal
Severity: feature
Version: 4.00.0
Target version: later
Category: typing
Related to: #7319
Child of: #5998
Monitored by: @hcarty

Bug description

Currently, if you have a GADT with multiple branches sharing the same type, eg:

type _ gadt =
| Float : float -> float gadt
| Float2 : float -> float gadt
| Int : int -> int gadt

then try to use Float and Float2 in one branch of a function:

let type_of_gadt : type t. t gadt -> string = function
| Float _ | Float2 _ -> "float"
| Int _ -> "int"

this will not pass the type checker, even though Float and Float2 have the same type:

Error: This pattern matches values of type float gadt
       but a pattern was expected which matches values of type t gadt

You would have to have each variant:

let type_of_gadt : type t. t gadt -> string = function
| Float _ -> "float"
| Float2 _ -> "float"
| Int _ -> "int"

or, matching with the default "_" will work since it's not an or-pattern, but this only works well if there is only one type in the GADT that has the problem:

let type_of_gadt : type t. t gadt -> string = function
| Int _ -> "int"
| _ -> "float"

It would be handy to be able to combine the branches for GADT constructors that refer to the same types.

@vicuna
Copy link
Author

vicuna commented Aug 22, 2012

Comment author: @garrigue

This one is a long-term goal.
To do that, one would need to know that the branches are equivalent,
but in the current implementation of GADTs there is no way to check that.
That is, we end up with two environments, we need to compare them,
and worse, we need to drop one of the two and still be safe for that branch...
Maybe we could use the summary, but this is still going to be difficult,
particularly if we are creating fresh skolem variables in both patterns.

@vicuna
Copy link
Author

vicuna commented Feb 18, 2017

Comment author: @xavierleroy

Moving to "later" based on @garrigue's comment.

@yallop
Copy link
Member

yallop commented Apr 5, 2019

It would be handy to be able to combine the branches for GADT constructors that refer to the same types.

This has been implemented in #2110, and the first version of the type_of_gadt function is now accepted as written, so I'm closing this.

@yallop yallop closed this as completed Apr 5, 2019
@trefis
Copy link
Contributor

trefis commented Apr 5, 2019

This hasn't quite been implemented: after #2110 you don't have the information that t = float outside the or-pattern.
We still hope to be able to do that in the future, but more work is required.

But I agree that the example given here is now accepted by the compiler indeed.

@yallop
Copy link
Member

yallop commented Apr 5, 2019

I see --- so the following example is not yet allowed:

let zero : type t. t gadt -> t = function
  | Float _ | Float2 _ -> 0.0
  | Int _ -> 0

@trefis: feel free to reopen if you think this is the best place to track that work.

@Octachron Octachron added the typing-GADTS GADT typing and exhaustiveness bugs label May 18, 2020
@vthemelis
Copy link

Will it ever be possible to pattern match by the type rather than the constructor? eg in pseudo-OCaml:

let zero : type t. t gadt -> t = function
  | _ when t = float -> 0.0
  | Int _ -> 0

@garrigue
Copy link
Contributor

Your syntax is confusing.
I suppose that you mean something like

let zero : type t. t gadt -> t = function
  | (_ : float gadt) -> 0.0
  | Int _ -> 0

expecting that it would automatically expand _ into all the cases compatible with float gadt.
That's an interesting idea, a bit related to the #-patterns for polymorphic variants.
However this would need a more precise definition (using only a type annotation seems brittle).
Maybe (#gadt : float gadt), insisting on the similarity.

@gasche
Copy link
Member

gasche commented Dec 27, 2021

If I follow, your idea is that #foo would expand to all the constructors of the datatype foo that are well-typed in the current context. However, I don't like the fact that this gives a non-modular semantics for type annotations: it feels wrong that (#foo : float foo) would be accepted in a place where (_ : float foo) or (x : float foo) are rejected.

(Note: we already have logic in place to explode wildcard patterns in situations that are different but related -- when checking refutation clauses.)

@Drup
Copy link
Contributor

Drup commented Dec 30, 2021

I've longed for such a feature several time. Simple syntax proposition: extend #<t> to any simple type expression, and expand when it's a sum type/gadt/polymorphic variant, as proposed above. It's consistent with the current version, which only accepts an identifier. When it's composed, we can simply use parens: #(float t).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature-wish typing typing-GADTS GADT typing and exhaustiveness bugs
Projects
None yet
Development

No branches or pull requests

8 participants