# Confusing Behaviour with Polymorphic Variants

**URL:** <https://discuss.ocaml.org/t/confusing-behaviour-with-polymorphic-variants/4098>\
**Category:** Learning\
**Created:** [July 15, 2019, 10:02am UTC](https://discuss.ocaml.org/t/confusing-behaviour-with-polymorphic-variants/4098 "2019-07-15T10:02:07Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![leamingrad](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/leamingrad/32/1616_2.png) [@leamingrad](https://discuss.ocaml.org/u/leamingrad)\
**Post date:** [July 15, 2019, 10:02am UTC](https://discuss.ocaml.org/t/confusing-behaviour-with-polymorphic-variants/4098/1 "2019-07-15T10:02:07Z")

</div>

I’m currently trying to modify some code that uses polymorphic variants, and am running into a strange issue.

The toy version of my problem is as follows (copying the output from `utop`):

```ocaml
module Test : sig
 val test : [> `Int] -> [> `Int | `Float]
end =
struct
 let test (input : [> `Int]) : [> `Int | `Float] = input
end;;
Error: Signature mismatch:
       Modules do not match:
         sig val test : ([> `Float | `Int] as 'a) -> 'a end
       is not included in
         sig val test : [> `Int] -> [> `Float | `Int] end
       Values do not match:
         val test : ([> `Float | `Int] as 'a) -> 'a
       is not included in
         val test : [> `Int] -> [> `Float | `Int]

```

What I don’t understand is why does the compiler not like the projection of the input into the larger type? I guess I am missing a subtlety here, but surely `[> 'Int]` is compatible with `[> 'Int | 'Float]`?

If I remove all of the `>` modifiers from the types, the example still fails, but I have kept them in here in case the resolution is different in this case.

If I just constantly return an `'Int` then everything works as expected:

```ocaml
module Test : sig
 val test : [> `Int] -> [> `Int | `Float]
end =
struct
 let test (input : [> `Int]) : [> `Int | `Float] = `Int
end;;
module Test : sig val test : [> `Int] -> [> `Float | `Int] end

```

Any help with this would be appreciated - either in understanding what the cause of the problem is, or in any workarounds (unfortunately I have to keep the polymorphic variants in the code, but maybe there are type hints or similar that could be added).

---

<div class="post-metadata">

**Author:** ![SkySkimmer](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/skyskimmer/32/1672_2.png) [@SkySkimmer](https://discuss.ocaml.org/u/SkySkimmer)\
**Post date:** [July 15, 2019, 10:57am UTC](https://discuss.ocaml.org/t/confusing-behaviour-with-polymorphic-variants/4098/2 "2019-07-15T10:57:20Z")

</div>

Consider what would happen if you did `test (`Float 0)`. The signature in your module type would accept it, but the value produced would have type `[`Float of int]` which is incompatible with `[`Float]`.

In order to prevent such issues, `[> `Foo]` is actually `[> `Foo] as 'a` for some fresh `'a`, which means "some `'a` with the constraint that it contains at least ``Foo`". So the signature you wrote means `test : 'a -> 'b` for any `'a` containing at least ``Int` and any `'b` containing at least ``Int` and ``Float`, and the one in the error message says `'a` and `'b` actually have to be the same thing (with the union of the constraints).

The confusing part is that `'a` doesn’t quite mean the same thing in a `val` vs in a `let ... in`: the following code (without polymorphic variants) produces an error even though it looks like we wrote the same type in the signature and in the implementation:

```ocaml
module M : sig
  val foo : 'a -> 'b
end = struct
  let foo : 'a -> 'b = fun x -> x
end

```

this is because in a letin variables like `'a` may be unified as necessary to make the type go through, but in a signature there’s no unification to do so they’re always independent.

---

<div class="post-metadata">

**Author:** ![n4323](https://avatars.discourse-cdn.com/v4/letter/n/97f17d/32.png) [@n4323](https://discuss.ocaml.org/u/n4323)\
**Post date:** [July 15, 2019, 11:18am UTC](https://discuss.ocaml.org/t/confusing-behaviour-with-polymorphic-variants/4098/3 "2019-07-15T11:18:17Z")

</div>

> [@SkySkimmer](#):
>
> Consider what would happen if you did `test (`Float 0)` .

Is it correct to conclude that if OCaml did not allow polymorphic variant constructors with the same name for different numbers of arguments (such as ` `Float` vs ` `Float of int`) then this problem would not exist?

---

<div class="post-metadata">

**Author:** ![SkySkimmer](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/skyskimmer/32/1672_2.png) [@SkySkimmer](https://discuss.ocaml.org/u/SkySkimmer)\
**Post date:** [July 15, 2019, 11:30am UTC](https://discuss.ocaml.org/t/confusing-behaviour-with-polymorphic-variants/4098/4 "2019-07-15T11:30:58Z")

</div>

You’d get the same kind of issue if you had `test : [>`Int] -> [> `Int | `Float of bool]` and passed ``Float 0` so no

---

<div class="post-metadata">

**Author:** ![n4323](https://avatars.discourse-cdn.com/v4/letter/n/97f17d/32.png) [@n4323](https://discuss.ocaml.org/u/n4323)\
**Post date:** [July 15, 2019, 11:40am UTC](https://discuss.ocaml.org/t/confusing-behaviour-with-polymorphic-variants/4098/5 "2019-07-15T11:40:57Z")

</div>

Ah yes. So going further, would the problem go away if all polymorphic constructors were required to use globally unique tags, so that ``Float of int` and ``Float of bool` in the same program would be rejected?

(Are such globally unique tags infeasible/undesirable?)

---

<div class="post-metadata">

**Author:** ![leamingrad](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/leamingrad/32/1616_2.png) [@leamingrad](https://discuss.ocaml.org/u/leamingrad)\
**Post date:** [July 15, 2019, 11:48am UTC](https://discuss.ocaml.org/t/confusing-behaviour-with-polymorphic-variants/4098/6 "2019-07-15T11:48:57Z")

</div>

@SkySkimmer: Thanks for the help with this. I think I understand a bit better, but I have a follow-up question if you have time to answer.

I’ve been looking a bit more, and it seems like an example without `'Float` also causes an error:

```ocaml
module Test : sig
val test : [> `Int] -> [> `Int]
end =
struct
let test input = input
end;;
Error: Signature mismatch:
      Modules do not match:
        sig val test : 'a -> 'a end
      is not included in
        sig val test : [> `Int] -> [> `Int] end
      Values do not match:
        val test : 'a -> 'a
      is not included in
        val test : [> `Int] -> [> `Int]

```

This doesn’t seem to fit the pattern, as I could call `test ('Float 0)` happily, but I couldn’t call `test ('Int 0)` to hit the same issue. Interestingly, this example works if you remove the `>`s, so it must be something to do with subtyping.

---

<div class="post-metadata">

**Author:** ![SkySkimmer](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/skyskimmer/32/1672_2.png) [@SkySkimmer](https://discuss.ocaml.org/u/SkySkimmer)\
**Post date:** [July 15, 2019, 12:01pm UTC](https://discuss.ocaml.org/t/confusing-behaviour-with-polymorphic-variants/4098/7 "2019-07-15T12:01:33Z")

</div>

``Float 0` still doesn’t fit in _every_ type `'b` containing ``Int`, it only fits in the specific one that was passed as input.

---

<div class="post-metadata">

**Author:** ![octachron](https://avatars.discourse-cdn.com/v4/letter/o/49beb7/32.png) [@octachron](https://discuss.ocaml.org/u/octachron)\
**Post date:** [July 15, 2019, 12:10pm UTC](https://discuss.ocaml.org/t/confusing-behaviour-with-polymorphic-variants/4098/8 "2019-07-15T12:10:41Z")

</div>

Another point is that the following function has the right type:

```auto
let test = function
| `Int -> `Int
| _ -> `Float

```

because it does not propagate the unknown variant tags, and thus it does not impose any shared constraints between the input and return type.

---

<div class="post-metadata">

**Author:** ![leamingrad](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/leamingrad/32/1616_2.png) [@leamingrad](https://discuss.ocaml.org/u/leamingrad)\
**Post date:** [July 15, 2019, 1:12pm UTC](https://discuss.ocaml.org/t/confusing-behaviour-with-polymorphic-variants/4098/9 "2019-07-15T13:12:57Z")

</div>

@SkySkimmer, @octachron: Thanks both. That makes more sense.
