Почему несвязанные переменные типа в объекте OCAML не отображаются при использовании типа класса?

Хотелось бы понять причину такого поведения объектов OCAML. Предположим, у меня есть класс A, который вызывает методы объекта другого класса B. Схематически A#f вызывает B#g и B#h. Обычная практика в ООП заключается в том, что я хотел бы избежать использования B в качестве фиксированного конкретного класса, а вместо этого объявить только интерфейс для B. Как лучше всего сделать это в OCAML? Я попробовал несколько вариантов, и я не совсем понимаю, почему одни из них работают, а другие нет. Вот примеры кода.

Версия 1:

 # class classA = object
    method f b = b#g + b#h 
   end ;;
 Error: Some type variables are unbound in this type:
     class a : object method f : < g : int; h : int; .. > -> int end
   The method f has type (< g : int; h : int; .. > as 'a) -> int where 'a
   is unbound

Такое поведение хорошо известно: OCAML правильно делает вывод, что bимеет тип открытого объекта но затем жалуется, что мой класс не объявляет никаких переменных типа. Таким образом, кажется, что класс Aдолжен иметь переменные типа; Затем я явно ввел переменную типа.

Версия 2:

 # class ['a] classA2 = object
   method f (b:'a) = b#g + b#h
   end ;;
 class ['a] classA2 :
   object constraint 'a = < g : int; h : int; .. > method f : 'a -> int end

Это работает, но класс теперь явно полиморфен с ограничением типа, как показывает OCAML. Также сбивает с толку то, что тип класса содержит переменную типа 'a, и все же я могу сказать let x = new classA2без указания значения типа для 'a.Почему это возможно?

Другой недостаток classA2заключается в том, что явное ограничение типа (b:'a)содержит переменную типа. В конце концов, я знаю, что bдолжен соответствовать фиксированному интерфейсу, а не неизвестному типу 'a. Я хочу, чтобы OCAML проверил правильность этого интерфейса.

Итак, в версии 3 я сначала объявил интерфейс classBкак тип класса, а затем объявил, что bдолжен быть этого типа:

 # class type classB = object method g:int method h:int end;;
 class type classB = object method g : int method h : int end
 # class classA3 = object method f (b:classB) = b#g + b#h end;;
 class classA3 : object method f : classB -> int end

Это тоже работает, но мое недоумение остается: почему classA3больше не требует явного полиморфизма?

Резюме вопросов:

  • Почему можно использовать новый classA2без указания типа для 'a, хотя classA2объявлен с переменная типа 'a?
  • Почему classA3принимает ограничение типа (b:classB)и больше не требует связанной переменной типа?
  • Отличаются ли функциональные возможности classA2и classA3каким-то тонким образом, и если да, то как?
7
задан winitzki 24 June 2012 в 13:07
поделиться