Наследование модулей и их тип - PullRequest
4 голосов
/ 30 января 2012

Я определил 2 подписи и 2 модуля следующим образом. Одна подпись получена из другой; один модуль является производным от другого.

module type MATRIX =
sig
  type 'a t
  ...
end

module type AMATRIX = 
sig
  include MATRIX
  ...
end

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

module AMatrixArray : AMATRIX =
struct
  include MatrixArray
  let init (x: 'a) : 'a t =
    Array.make 2 (Array.make 2 x)
  ...
end

Но когда я это скомпилирую, в конце выдает ошибку Error: This expression has type 'a array array but an expression was expected of type 'a t = 'a MatrixArray.t.

Кто-нибудь знает, как я мог сохранить это наследство и сделать тип 'a t = 'a array array распознанным?

Ответы [ 3 ]

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

В коде:

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

Вы заставляете MatrixArray скрыть определение 'a t.Один из способов решения вашей проблемы - снять ограничение подписи:

module MatrixArray = struct
  type 'a t = 'a array array
 ...
end

. Позже вы можете заменить MatrixArray на (MatrixArray : MATRIX), если хотите абстрагировать тип t.

2 голосов
/ 14 февраля 2012

Будьте осторожны с слишком большим количеством абстракций: хорошо скрывать типы (то есть использовать абстрактные типы), но компилятор OCaml использует типы манифеста для выполнения некоторых оптимизаций. Абстрагирование типов будет препятствовать их выполнению компилятором.

Один пример, который может быть интересен в вашем случае, состоит в том, что OCaml имеет два представления массивов: стандартные и плоские массивы с плавающей точкой. Если компилятор знает тип элементов в массиве, он может напрямую обращаться к массиву, используя правильное представление. Но если типы элементов являются абстрактными, компилятор добавит тест для выбора между двумя представлениями.

Если вы работаете с матрицами чисел с плавающей точкой, вы должны сохранять манифест типов, чтобы компилятор генерировал наиболее эффективный код при доступе к этим массивам.

Пример:

let init_array t x =
  for i = 0 to Array.length t - 1 do
    t.(i) <- x
  done

намного медленнее (в нативном коде), чем

let init_float_array t (x : float) =
  for i = 0 to Array.length t - 1 do
    t.(i) <- x
  done

, поскольку init_array является полиморфным, а init_float_array - мономорфным для массивов с плавающей точкой.

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

На самом деле, MatrixArray немного больше, чем просто MATRIX: это MATRIX, где реализация типа t, как известно, является массивом.Таким образом, вы можете написать:

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

Таким образом, вы сохраняете ограничение MATRIX и можете обнаруживать ошибки типа, а также хранить информацию о том, что тип на самом деле - конечно, при условии, что вы заботитесьо том, чтобы сделать тип открытым, а не абстрактным.

...