Необходимость и невозможность иметь тип подписи - PullRequest
1 голос
/ 30 января 2012

Я определил 2 подписи и 4 модуля следующим образом, и он отлично работает:

module type TRIANGLE =
  sig
    type 'a t
    val get ...
    val set ...
    ...
  end

module type MATRIX =
  sig
    type 'a t
    val unionArrayArray: 'a TriangleArray.t -> 'a TriangleArray.t -> 'a t
    val unionListList: 'a TriangleList.t -> 'a TriangleList.t -> 'a t
    val unionArrayList: 'a TriangleArray.t -> 'a TriangleList.t -> 'a t
    val unionListArray: 'a TriangleList.t -> 'a TriangleArray.t -> 'a t
    ...
  end

module rec MatrixArray: MATRIX =
  struct
    type 'a t = 'a array array
    ...
  end

and MatrixList: MATRIX =
  struct
    type 'a t = 'a list list
    ...
  end

and TriangleArray: TRIANGLE =
  struct
    type 'a t = 'a array array
    ...
  end

and TriangleList: TRIANGLE =
  struct
    type 'a t = 'a list list
    ...
  end

TRIANGLE и MATRIX - две параллельные подписи.Функция unionXXXX принимает два прямоугольных треугольника, если их стороны имеют одинаковую длину, строит матрицу.

Модуль XXXXArray внутренне реализован массивом массивов, а модуль XXXXList внутренне реализован списком списка.Но они могут иметь такую ​​же сигнатуру XXXX, которая включает в себя такие функции, как set, get ...

. Проблема этой конструкции заключается в том, что с такими функциями, как set, getTRIANGLE, 4 unionXXXX функции могут иметь одинаковую реализацию.Нам нужна только одна функция union, и ее тип на самом деле : 'a TRIANGLE.t -> 'a TRIANGLE.t -> 'a MATRIX.t.

Но если я определю сигнатуру MATRIX следующим образом, компилятор остановится на сигнатуре union и выдаст Error: Unbound module Triangle:

module type TRIANGLE =
  sig
    type 'a t
    val get ...
    val set ...
    ...
  end

module type MATRIX =
  sig
    type 'a t
    val union: 'a TRIANGLE.t -> 'a TRIANGLE.t -> 'a t
    ...
  end

Надеюсь, я показал, что лучше объединить 4 unionXXXX функции в одну union, но очень жаль, что мы не можем указать его тип из-заотсутствие 'a TRIANGLE.t, либо в подписи MATRIX, либо в модулях MatrixXXXX.

Я надеюсь, что мои потребности и заботы были четко описаны, и есть ли у кого-нибудь решение или лучший дизайн?

Edit1 : изменить регистр букв в соответствии с комментарием ...

1 Ответ

2 голосов
/ 30 января 2012

Во-первых, несколько слов о соглашениях: обычно ожидается, что имена модулей имеют CamelCase форматирование, а имена типов модулей имеют ALL_UPPERCASE форматирование.Мне потребовалось два чтения, чтобы заметить, что вы имели дело с типами модулей вместо модулей.

Итак, вы пытаетесь сказать, что любой модуль, который реализует тип модуля MATRIX, должен иметь возможность, для любого модуля Triangle, который реализует TRIANGLE, предоставить этоподпись:

type 'a t
val union : 'a Triangle.t -> 'a Triangle.t -> 'a t

Невозможно выразить универсальные кванторы таким образом.Что вы должны сделать, это использовать экзистенциальный квантификатор и функтор:

module type MATRIX = sig
  module Triangle : TRIANGLE 
  type 'a t 
  val union : 'a Triangle.t -> 'a Triangle.t -> 'a t
end

module MatrixOfTriangle = functor (Triangle:TRIANGLE) -> struct
  module Triangle = Triangle
  type 'a t = ...
  let union t1 t2 = ...
end

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

...