Параметричен локално абстрактен тип

Опитвам се да разбера как да напиша функция в зависимост от модул с параметричен тип, но не мога да намеря нищо подобно никъде. Опитах се да намаля проблема колкото е възможно повече и завърших с този фиктивен пример.

module type Mappable = sig
  type 'a t
  val map : ('a -> 'b) -> 'a t -> 'b t
end

let plus (type m) (module M : Mappable with type 'a t = 'a m) (xs : int m) = 
  M.map (fun x -> x + 1) xs

което дава грешка Error: Syntax error: module-expr expected.

Ако изпусна 'a, ще получа следната грешка.

Error: In this `with' constraint, the new definition of t
       does not match its original definition in the constrained signature:
       Type declarations do not match: type t is not included in type 'a t
       They have different arities.

Какъв е правилният синтаксис за това?


person tomferon    schedule 03.02.2016    source източник


Отговори (3)


Вярвам, че това, което искате да направите тук, е невъзможно в OCaml 4.02.3. Нека видим опростена версия без променливата тип:

module type Mappable = sig
  type t
  val map : ('a -> 'b) -> t -> t
end

let plus (type m) (module M : Mappable with type t = m) (xs : m) = 
  M.map (fun x -> x + 1) xs

Горното може да се въведе и plus има следния тип:

val plus : (module Mappable with type t = 'm) -> 'm -> 'm

типът m в неговата дефиниция е абстрахиран до променлива 'm.

Сега се върнете към вашия оригинален код и помислете какво трябва да има типът plus. Тъй като се опитвате да абстрахирате m от (type m), трябва да бъде:

val plus : (module Mappable with type 'a t = 'a 'm) -> 'a 'm -> 'a 'm

За съжаление, OCaml не поддържа полиморфизъм с по-висок вид, който позволява тази форма от тип 'a 'm. Изглежда, че въвеждането на първи клас модул е ​​внимателно внедрено, за да не се въвежда.

Можете да видите следната кратка статия, която обяснява текущото (нещастно) състояние на полиморфизма с по-висок вид в OCaml. Това обяснява заобиколно решение: как да го кодирате в текущата рамка OCaml с цената на изрични принуди:

https://ocamllabs.github.io/higher/lightweight-higher-kinded-polymorphism.pdf

Никога не съм опитвал сам, но същото решение може да се приложи към вашия пример.

person camlspotter    schedule 03.02.2016

Не е възможно в OCaml, тъй като ограничението за тип не е ограничение за тип на обикновен модул, а специално синтактична конструкция, която не позволява полиморфни типове:

Синтактичният клас от тип пакет, който се появява в израза за тип ( тип пакет на модул ) и в анотираните форми, представлява подмножество от типове модули. Това подмножество се състои от наименувани типове модули с незадължителни ограничения от ограничена форма: могат да бъдат посочени само непараметризирани типове.

Обичайно решение би било да се създаде модул, който свързва всички променливи на типа с конкретни типове:

module type Mapper = sig 
  type a
  type b
  type src
  type dst
  val map : (a -> b) -> src -> dst
end

let plus (type src) (type dst)
    (module M : Mapper with type dst = dst
                        and type src = src
                        and type a = int
                        and type b = int) (xs : src) : dst =
  M.map (fun x -> x + 1) xs

Във вашия конкретен пример няма нужда да свързвате 'a и 'b, тъй като те по същество не се използват, така че може да се опрости до:

module type Mapper = sig 
  type src
  type dst
  val map : ('a -> 'b) -> src -> dst
end

let plus (type src) (type dst)
    (module M : Mapper with type dst = dst
                        and type src = src) (xs : src) : dst =
  M.map (fun x -> x + 1) xs

Разбира се, това е много ограничаващо, но това е възможното днес.

person ivg    schedule 03.02.2016

Ако искате да предадете модули на функции, трябва да използвате вместо това функтори:

module F (M : Mappable) = struct
  let plus xs = M.map (fun x -> x + 1) xs
end
person Thomash    schedule 04.02.2016