Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

OCaml types with different levels of specificity

I am attempting to simulate an interface in OCaml and am using the "type" construct. I have two types:

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

...and would like to define a particular fooSansBar:

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

...but am told that the bar field is not defined. From this, it appears that, contrary to the values I passed in matching fooSansBar's signature, the system believes I am trying to create a fooConBar. Is it possible to create a fooSansBar if the two types as defined above exist?

Additionally (because I'm new to OCaml) is there a better way to simulate an interface?

like image 962
Mat Kelly Avatar asked Mar 21 '09 17:03

Mat Kelly


2 Answers

In OCaml, field names in record types must be unique, so the two types you define cannot coexist simultaneously. Caml is the only language I know with this property.

Because the second definition hides the first, when the compiler sees the a and b fields it expects them to belong to the fooConBar type and so complains of the missing bar field.

If you are trying to simulate an interface, the correct functional way to do it in Caml is to define a module type.

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

And an instance:

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

With modules and module types you also get subtyping; there's no need to resort to objects.

P.S. My Caml is rusty; syntax may be off.

like image 135
Norman Ramsey Avatar answered Oct 29 '22 03:10

Norman Ramsey


There are several possible solutions in OCaml depending how you're using the code you gave. The simplest is to combine the two types:

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

Another solution is to replace the records with objects because objects support subtyping (and can have their types inferred so there is no need to declare a type!):

# 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)
like image 33
J D Avatar answered Oct 29 '22 01:10

J D