From: Anton Bachin <antronbachin@gmail.com>
To: "caml-list@inria.fr users" <caml-list@inria.fr>
Subject: [Caml-list] GADT+polymorphic variants quirk
Date: Tue, 27 Dec 2016 14:04:59 -0600 [thread overview]
Message-ID: <B2CFF70E-5424-48DE-9DC7-6E9F36259B60@gmail.com> (raw)
Hello,
Consider this code for simulating an ad-hoc polymorphic addition
function:
type whole = [ `Integer ]
type general = [ whole | `Float ]
type _ num =
| I : int -> [> whole ] num
| F : float -> general num
module M :
sig
val add : ([< general ] as 'a) num -> 'a num -> 'a num
val to_int : whole num -> int
val to_float : general num -> float
end =
struct
let add : type a. a num -> a num -> a num = fun a b ->
match a, b with
| I n, I m -> I (n + m)
| F n, I m -> F (n +. float_of_int m)
| F n, F m -> F (n +. m)
| _ ->
(* ----NOTE---- *)
match b, a with
| F m, I n -> F (float_of_int n +. m)
| _ -> assert false
let to_int : whole num -> int = fun (I n) -> n
let to_float = function
| I n -> float_of_int n
| F n -> n
end
let () =
M.add (I 1) (I 2) |> M.to_int |> Printf.printf "%i\n";
M.add (I 1) (F 2.) |> M.to_float |> Printf.printf "%f\n"
Instead of the nested match expression (marked with (* NOTE *)), I would
have expected to just write
| I n, F m -> ...
However, if I actually do that, the result is an error on the expression
in the case:
Error: This expression has type general num
but an expression was expected of type a num
Type general = [ `Float | `Integer ] is not compatible with type
a = [> `Integer ]
The second variant type does not allow tag(s) `Float
While the reversed case type-checks successfully. I can imagine why this
would be so, but I want to ask the experts on the mailing list.
Is this a known quirk of the typechecker? A bug? Is there some
alternative syntax I am missing that would allow the I n pattern to be
written first?
Note that there is a way to rewrite the nested match cases to avoid _
and maintain the exhaustiveness check. I wrote them out as above for
clarity. The actual solution I have settled on for now is:
let add : type a. a num -> a num -> a num = fun a b ->
match a, b with
| I n, I m -> I (n + m)
| F n, I m -> F (n +. float_of_int m)
| _, F m ->
match a with
| I n -> F (float_of_int n +. m)
| F n -> F (n +. m)
Best,
Anton
P.S. If interested, the code was for this Stack Overflow question:
http://stackoverflow.com/questions/41214000
answer:
http://stackoverflow.com/a/41334879/2482998
next reply other threads:[~2016-12-27 20:05 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-12-27 20:04 Anton Bachin [this message]
2017-01-02 13:51 ` Jacques Garrigue
2017-01-03 14:05 Nils Becker
2017-01-03 15:09 ` Anton Bachin
2017-01-03 15:22 ` Anton Bachin
2017-01-06 1:39 ` Jacques Garrigue
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=B2CFF70E-5424-48DE-9DC7-6E9F36259B60@gmail.com \
--to=antronbachin@gmail.com \
--cc=caml-list@inria.fr \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox