Типы OCaml с разными уровнями специфичности - PullRequest
9 голосов
/ 21 марта 2009

Я пытаюсь смоделировать интерфейс в OCaml и использую конструкцию типа. У меня есть два типа:

type fooSansBar = {a: string; b: int};;
type fooConBar = {a:string; b:int; bar:char};;

... и хотел бы определить конкретный fooSansBar:

let fsb = {a="a"; b=3};;

... но мне говорят, что поле бара не определено. Из этого следует, что, вопреки значениям, которые я передал в соответствии с сигнатурой fooSansBar, система считает, что я пытаюсь создать fooConBar. Можно ли создать fooSansBar, если существуют два типа, как определено выше?

Кроме того (потому что я новичок в OCaml), есть ли лучший способ симулировать интерфейс?

Ответы [ 5 ]

9 голосов
/ 22 марта 2009

В OCaml имена полей в типах записей должны быть уникальными, поэтому два определяемых вами типа не могут сосуществовать одновременно. Caml - единственный язык, на котором я знаю это свойство.

Поскольку второе определение скрывает первое, когда компилятор видит поля a и b, он ожидает, что они принадлежат типу fooConBar, и поэтому жалуется на отсутствующее поле bar.

Если вы пытаетесь смоделировать интерфейс, правильный функциональный способ сделать это в Caml - определить module type.

module type FOO_CON_BAR = sig
  val a : string
  val b : int
  val bar : char
end

И экземпляр:

module Example = struct
  let a = "hello"
  let b = 99
  let c = '\n'
end

С модулями и типами модулей вы также получаете подтипы; нет необходимости прибегать к объектам.

P.S. Мой Caml ржавый; синтаксис может быть отключен.

4 голосов
/ 06 мая 2009

В OCaml есть несколько возможных решений в зависимости от того, как вы используете код, который вы дали. Проще всего объединить два типа:

type fooBar = { a: string; b: int; bar: char option }

Другое решение заключается в замене записей объектами, поскольку объекты поддерживают подтипы (и могут иметь свои типы, поэтому нет необходимости объявлять тип!):

# let fsb = object
    method a = "a"
    method b = 3
  end;;
val fsb : < a : string; b : int > = <obj>

# fsb#a, fsb#b;;
- : string * int = ("a", 3)
3 голосов
/ 21 марта 2009

Второй тип переопределяет a и b, эффективно скрывая первый, поэтому его нельзя больше строить. Вы можете определить эти типы в разных модулях, но это будет то же самое, что использовать разные имена для a и b.

Эти конструкции можно использовать только тогда, когда вы не пытаетесь «наследовать» от другого интерфейса, а просто реализуете его.

Если вы хотите использовать эти объектно-ориентированные концепции в Ocaml, вы можете взглянуть на объектную систему или, в зависимости от вашей проблемы, на модульную систему. В качестве альтернативы, вы можете попытаться решить вашу проблему функциональным способом. Какую проблему вы пытаетесь решить?

2 голосов
/ 24 ноября 2010

OCaml предоставляет два способа реализации интерфейсов. Один, как уже упоминалось, это тип модуля.

Другой тип класса. Вы можете написать тип класса (интерфейс) fooSansBar:

class type fooSansBar = object
    method a: string
    method b: int
end

и тип класса fooConBar:

class type fooConBar = object
    inherit fooSansBar
    method bar: char
end

Это позволит вам использовать fooConBar везде, где требуется fooSansBar. Теперь вы можете создать fooSansBar, используя вывод типа:

let fsb = object
    method a = "a"
    method b = 3
end

Теперь тип fsb, по словам Джона, <a: string; b: int>, но его вполне можно использовать как fooSansBar из-за структурного подтипа OCaml.

1 голос
/ 23 ноября 2010

В OCaml невозможно иметь два типа записей с пересекающимися наборами полей, присутствующими в одной и той же области видимости.

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

module FooSansBar = struct type t = {a:string; b:int} end
module FooConBar = struct type t = {a:string; b:int; bar:char} end

Затем вы можете создать экземпляры этих типов следующим образом:

let fsb = {FooSansBar.a="a"; b=3}
let fcb = {FooConBar.a="a"; b=4; bar='c'}

Эти экземпляры имеют следующие типы:

fsb : FooSansBar.t 
fcb : FooConBar.t
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...