Тип в подписи, используемый для другой подписи - PullRequest
0 голосов
/ 29 января 2012

Более ясная версия этого вопроса была опубликована здесь .

Я определил подпись и два модуля следующим образом. Причина для определения 2-х модулей заключается в том, что я могу использовать MatrixArray или MatrixList в зависимости от контекста ...

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

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

module MatrixList =
  (struct
    type 'a t = 'a list list
    ...
  end: MATRIX)

Затем я определяю другую подпись и еще 2 модуля, которые относятся к MATRIX, MatrixArray и MatrixList:

module type PM =
  sig
    type 'a t
    (* val of_matrix: 'a MatrixArray.t -> 'a t *)
    val of_matrix: 'a MATRIX.t -> 'a t
    ...
  end

module PmArray =
  (struct
    type 'a t = 'a array array
    let of_matrix (m: 'a MatrixArray.t) : 'a t =
    ...
  end: PM)

module PmList =
  (struct
    type 'a t = 'a list list
    let of_matrix (m: 'a MatrixList.t) : 'a t =
    ...
  end: PM)

В подписи PM я могу определить val of_matrix: 'a MatrixArray.t -> 'a t, но не могу определить val of_matrix: 'a MATRIX.t -> 'a t (Error: Unbound module MATRIX). Так что я думаю MATRIX.t всегда незаконно ...

То, что я действительно хочу реализовать, это ... на уровне подписи, of_matrix: 'a MATRIX.t -> 'a PM.t, но на уровне модуля PmArray, of_matrix: 'a MatrixArray.t -> 'a PmArray.t; на уровне модуля PmList, of_matrix: 'a MatrixList.t -> 'a PmList.t.

Я не знаю, нужно ли мне определять дополнительные модули или функторы для реализации этой структуры ... Надеюсь, моя проблема хорошо описана, кто-нибудь может помочь?

Edit1:

Я просто понимаю, что имя of_matrix может вводить в заблуждение, например, его назвали бы просто f. Он представляет собой просто функцию типа 'a MatrixArray.t -> 'a PmArray.t или 'a MatrixList.t -> 'a PmList.t, ее реализация внутри может быть сложной. И я хотел бы сделать его тип 'a MATRIX.t -> 'a PM.t, что, к сожалению, не разрешено.

Edit2:

Я бы назвал PM, например, TRIANGLE, и назвал бы PmArray TriagleArray (что означает треугольник, представленный массивом массива), и назвал бы PmList TriangleList (что означает треугольник, представленный списком списка). Учитывая матрицу m, функция f (m: a MatrixArray.t) : 'a TriangleArray.t получает свою левую верхнюю половину, разделенную диагональной линией.

На текущем этапе такие функции, как : 'a MatrixArray.t -> 'a TriangleList.t, на самом деле не нужны, хотя нет причин исключать их позже ... На уровне модуля мне действительно нужны : a MatrixArray.t -> 'a TriangleArray.t и : a MatrixList.t -> 'a TriangleList.t, и я просто хотел бы иметь общую подпись / ограничение для них: 'a MATRIX.t -> 'a TRIANGLE.t где-то.

1 Ответ

1 голос
/ 29 января 2012

Основная проблема в том, что 'a MATRIX.t не является типом, поэтому его нельзя использовать для создания новых типов функций.Это означает, что объявление val 'a MATRIX.t -> 'a t не является допустимым определением функции.

Сигнатуры типов определяют только ограничения для типов.В большинстве случаев вам не понадобятся сигнатуры типов, потому что они могут быть легко получены из самих модулей.Основная причина использования сигнатур типов заключается в том, что вы планируете функторизовать свой код позже.В этом случае вам нужно определить сигнатуру типа, которую вы хотите использовать в качестве входных и выходных данных для вашего функтора.Будут разрешены все модули, соответствующие этой подписи, независимо от того, относятся ли они к указанному типу.OCaml действительно использует Duck Typing на уровне модулей и объектов.

Таким образом, самое простое решение - полностью избавиться от сигнатуры PM модуля.Это также уменьшит объем кода, который не имеет реальной семантики.Если вам действительно нужна подпись модуля (или вы просто играете с модулями в настоящее время).

Вот одно из возможных решений вашей проблемы:

module type MATRIX =
  sig
    type 'a t
  end

module MatrixArray =
  (struct
    type 'a t = 'a array array
    type 'a b = 'a
  end: MATRIX)

module MatrixList =
  (struct
    type 'a t = 'a list list
  end: MATRIX)

  module type PM =
  sig
    type 'a t

  end

module Pm  = functor ( M: MATRIX) ->
  (struct
    type 'a t = 'a M.t
  end: PM with type 'a t = 'a M.t ) 

module PmArray = Pm(MatrixArray)
module PmList = Pm(MatrixList)

Не то, чтобы предложение with вводило типэквивалентность между типом параметра 'a MATRIX.t (на самом деле не типом, но становится единым, когда создается экземпляр функтора) и результирующим типом 'a PM.t (опять же, на самом деле не типом).Следовательно, при создании экземпляра функтора необходимые равенства сохранятся, и ваша функция of_matrix не понадобится.

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

...