Объединение параметров c полиморфизм и полиморф c варианты (типы backtick) - PullRequest
5 голосов
/ 21 января 2020

Предположим, у меня есть тип, состоящий из нескольких полиморфных c вариантов (ковариантно), таких как:

[> `Ok of int | `Error of string]

Предположим далее, что я хочу преобразовать это определение в некий конструктор типов и тип бетона int. Моей первой попыткой было следующее:

type 'a error = [> `Ok of 'a | `Error of string]

Тем не менее, использование такого определения приводит к действительно странной ошибке типа с упоминанием переменной типа 'b, которая нигде не появляется в определении.

$ ocaml
        OCaml version 4.07.0

# type 'a error = [> `Ok of 'a | `Error of string ];;
Error: A type variable is unbound in this type declaration.
In type [> `Error of string | `Ok of 'a ] as 'b the variable 'b is unbound

Это 'b является автоматически сгенерированным именем, добавление явного 'b смещает переменную в 'c.

$ ocaml
        OCaml version 4.07.0

# type ('a, 'b) error = [> `Ok of 'a | `Error of 'b ];;
Error: A type variable is unbound in this type declaration.
In type [> `Error of 'b | `Ok of 'a ] as 'c the variable 'c is unbound

Использование инвариантной конструкции [ `Thing1 of type1 | `Thing2 of type 2 ], кажется, прекрасно работает в этом context.

$ ocaml
        OCaml version 4.07.0

# type 'a error = [ `Ok of 'a | `Error of string ] ;;
type 'a error = [ `Error of string | `Ok of 'a ]
#

Однако явная пометка параметра type как ковариантного не спасает исходный пример.

$ ocaml
        OCaml version 4.07.0

# type +'a error = [> `Ok of 'a | `Error of string];;
Error: A type variable is unbound in this type declaration.
In type [> `Error of string | `Ok of 'a ] as 'b the variable 'b is unbound

И, просто, добавление аннотации контравариантности также не работа.

$ ocaml
        OCaml version 4.07.0

# type -'a error = [> `Ok of 'a | `Error of string];;
Error: A type variable is unbound in this type declaration.
In type [> `Error of string | `Ok of 'a ] as 'b the variable 'b is unbound

Попытка угадать имя, которое компилятор будет использовать для переменной несвязанного типа, и добавление его в качестве параметра слева также не работает и выдает очень странное сообщение об ошибке.

$ ocaml
        OCaml version 4.07.0

# type ('a, 'b) string = [> `Ok of 'a | `Error of string] ;;
Error: The type constructor string expects 2 argument(s),
       but is here applied to 0 argument(s)

Есть ли способ сделать конструктор типов, который может эффективно "заменять различные типы" на int в [> `Ok of int | `Error of string]?

1 Ответ

6 голосов
/ 21 января 2020

Это не проблема дисперсии или параметрического полиморфизма c, а полиморфизм строк. Когда вы добавляете > или <, он также добавляет переменную неявного типа, переменную строки, которая будет содержать «полный» тип. Вы можете увидеть эту переменную типа в явном виде в ошибке:

[> `Error of string | `Ok of 'a ] as 'b

Обратите внимание на часть as 'b в конце.

Чтобы создать псевдоним типа, необходимо сделать переменную типа явный, так что вы можете ссылаться на него как параметр типа в псевдониме:

type ('a, 'r) error = [> `Ok of 'a | `Error of string ] as 'r

Обратите внимание также, что если у вас есть или когда вы столкнетесь с объектами, то это также применимо и здесь. Тип объекта с .. имеет переменную неявного типа, которую необходимо сделать явным, чтобы присвоить ей псевдоним:

type 'r obj = < foo: int; .. > as 'r
...