OCaml defining and implementing interface - ocaml

Let's have such code
module type INTERFACE =
sig
val function_that_must_be_implemented : int -> int
end
module Implementation : INTERFACE =
struct
let function_that_must_be_implemented x = x
end
Is any way to describe the same thing but using OCaml classes? I want to have a class that implements such interface.

There is something called a class type:
class type interface = object method method_I_want : int end
Then you can implement it:
class implementation : interface = object
method method_I_want = 14
end
You can indeed instantiate this class:
# let abc = new implementation;;
val abc : implementation = <obj>
# abc#method_I_want;;
- : int = 14

Related

Issue inferring type for generic

I have a c library that I bind to, which has many structs that hold data of different types.
#[Link("foo")]
lib LibFoo
struct IntStruct
data : LibC::Int
end
struct DoubleStruct
data : LibC::Double
end
fun get_int_struct(n : LibC::SizeT) : IntStruct*
fun get_double_struct(n : LibC::SizeT) : DoubleStruct*
end
I have a generic class where I want the type T to be the type of one of those structs, based off of an input array.
class GenericClass(T)
#ptr : Pointer(T)
#obj : T
def initialize(arr : Array)
#ptr = infer_type(arr)
#obj = #ptr.value
end
end
Where infer_type looks like:
def infer_type(data : Array(Int32))
return LibFoo.get_int_struct(data.size)
end
def infer_type(data : Array(Float64))
return LibFoo.get_double_struct(data.size)
end
The code works fine when I explicitly set the type...
GenericClass(LibFoo::IntStruct).new [1, 2, 3, 4, 5]
...but I would like to infer the type.
Maybe providing a custom generalized new method works for you?
struct A
end
struct B
end
class Generic(T)
def self.new(items : Array(A)) forall A
new(fetch_struct(items))
end
private def initialize(#struct : T)
end
private def self.fetch_struct(items : Array(Int32))
A.new
end
private def self.fetch_struct(items : Array(Float64))
B.new
end
end
p Generic.new([1])
p Generic.new([1.0])
https://carc.in/#/r/7s6d

Circular dependency reasonml

Let's say that I have a 1 -> n relation: one todo can has many (or zero) notes and a note can have zero or one todo. How can I achieve this relation in ReasonML? (binding for an external lib)
Here is what I have come with at the moment (which is of course not working)
module Note = {
module Attributes = {
[#bs.deriving abstract]
type t = {
[#bs.optional]
id: float,
[#bs.optional]
text: string,
[#bs.optional]
todo: Todo.Attributes.t,
};
};
};
module Todo = {
[#bs.deriving abstract]
type t = {
[#bs.optional]
id: float,
[#bs.optional]
title: string,
[#bs.optional]
completed: bool,
[#bs.optional]
notes: array(Note.Attributes.t),
};
};
let todo = Todo.Attribute.t(~title="hello");
What if Note and Todo are in one file, an are in separated files?
I am not familliar with Reason but in OCaml, one would do this kind of stuff using mutually recursive module, as in the following minimal example.
Using mutally recursive requires to defines their module type:
module type NoteSig = sig
type t
end
module type TodoSig = sig
type t
end
and the actual modules:
module rec Note : NoteSig = struct
type t = {
todo: Todo.t
}
end
and Todo : TodoSig = struct
type t = {
notes: Note.t array
}
end
If you prefer both module to be in a separate file, you can do pretty much the same thing using functors (still using the module signatures, let's say in a file sig.ml):
a.ml:
module Note (T:Sig.TodoSig) = struct
type t = {
todo: T.t
}
end
b.ml:
module Todo (N:Sig.NoteSig) = struct
type t = {
notes: N.t array
}
end
You can now instanciate your modules in an other file :
c.ml:
module rec NoteImpl = (A.Note(TodoImpl):NoteSig)
and TodoImpl = (B.Todo(NoteImpl):TodoSig)
I can only suppose there is a way to to do the same thing in Reason, probably by adding a lot of brackets everywhere. Hope it helps.

Work with class in OCaml

I want create function with my type test_type in class t. My code:
type test_type = [`t1|`t2]
let get_types =
function
| `t1 -> "t1"
| `t2 -> "t2";;
class type class_types =
object
method t_types : test_type
method test : (string -> string -> test_type -> unit) -> unit
end;;
class t : class_types =
object
method test par1 ?(par2="no par2") ?(par3=`t1) () =
print_endline("--->"^par1);
print_endline("--->"^par2);
print_endline("--->"^get_types par3)
end;;
let t_run = new t;;
t_run # test "parametr1" ~par3:`t2 ();;
is return error
The class type is not matched by the class type class_types
The first class type has no method t_types
How to do this?
Simply your implementation of t lacks the method t_types, which is defined in the class type class_types.
In addition to this, method test's type is string -> ?par2: string -> ?par3: test_type -> unit -> unit, which is incompatible with one at the class type.

Mutually recursive module and functor in OCaml

I have defined an interface A to be used by several functors, and notably by MyFunctor :
module type A = sig
val basic_func: ...
val complex_func: ...
end
module MyFunctor :
functor (SomeA : A) ->
struct
...
let complex_impl params =
...
(* Here I call 'basic_func' from SomeA *)
SomeA.basic_func ...
...
end
Now I want to define a module B with implements the interface A. In particular, the implementation of complex_func should use basic_func through complex_impl in MyFunctor :
module B = struct
let basic_func = ...
let complex_func ... =
let module Impl = MyFunctor(B) in
Impl.complex_impl ...
end
However, this code doesn't compile as B is not fully declared in the context of MyFunctor(B). Obviously B depends on MyFunctor(B), which itself depends on B, so I tried to use the rec keyword on module B, but it didn't work out.
So, is it possible to do something like this ? It would be useful as I have several modules B_1, ..., B_n that use the same implementation of B_k.complex_func in terms of B_k.basic_func.
Or is there a better pattern for my problem ? I know that I can declare complex_impl as a regular function taking basic_func as a parameter, without using a functor at all :
let complex_impl basic_func params =
...
basic_func ...
...
But in my case complex_impl uses many basic functions of A, and I think that the paradigm of functors is clearer and less error-prone.
Edit : I followed this answer, but in fact, A uses some type t that is specialized in B :
module type A = sig
type t
val basic_func: t -> unit
val complex_func: t -> unit
end
module MyFunctor :
functor (SomeA : A) ->
struct
let complex_impl (x : SomeA.t) =
SomeA.basic_func x
...
end
module rec B : A = struct
type t = int
val basic_func (x : t) = ...
val complex_func (x : t) =
let module Impl = MyFunctor(B) in
Impl.complex_impl x
end
And now I get the error (for x at line Impl.complex_impl x) :
This expression has type t = int but an expression was expected of type B.t
Edit 2 : I solved this second problem with the following code :
module rec B :
A with type t = int
= struct
type t = int
...
end
You can use recursive modules just like you'd write recursive let bindings
module type A = sig
val basic_func : unit -> int
val complex_func : unit -> int
end
module MyFunctor =
functor (SomeA : A) ->
struct
let complex_impl = SomeA.basic_func
end
module rec B : A = struct
let basic_func () = 0
let complex_func () =
let module Impl = MyFunctor(B) in
Impl.complex_impl ()
end
Note (a) the module rec bit in the definition of B and (b) that I am required to provide a module signature for a recursive module definition.
# B.basic_func ();;
- : int = 0
# B.complex_func ();;
- : int = 0
There's a small caveat, however, in that this only works because the signature A has only values which are function types. It is thus known as a "safe module". If basic_func and complex_func were values instead of function types then it would fail upon compilation
Error: Cannot safely evaluate the definition
of the recursively-defined module B

Typing in ocaml methods

I was playing with method redefinition, and I found this silly example :
class a =
object
method get (x : a) = x
end
class b =
object
inherit a
method get (x : b) = x
end
I'm clearly specifying that I want the get method from the b class to take a b and return a b, but the method signature is a -> a. And if I do
(new b)#get(new a)
he's very happy, when he really shouldn't. After that I added something silly :
class a =
object
method get (x : a) = x
end
class b =
object
inherit a
method get (x : b) = x#foo(x)
method foo (x : a) = x
end
And I get Error: This expression has type b
It has no method foo
What on earth is happening ?
Taking the first example first: OCaml has structural typing of objects, not nominal typing. In other words, the type of an object is determined entirely by its methods (and their types). So the classes a and b are in fact the same type.
$ ocaml
OCaml version 4.00.0
# class a = object method get (x: a) = x end;;
class a : object method get : a -> a end
# class b = object inherit a method get (x: b) = x end;;
class b : object method get : a -> a end
# let a0 = new a;;
val a0 : a = <obj>
# let b0 = new b;;
val b0 : b = <obj>
# (a0: b);;
- : b = <obj>
# (a0: a);;
- : a = <obj>
# (b0: a);;
- : a = <obj>
# (b0: b);;
- : b = <obj>
#
(What I'm trying to show here is that both a0 and b0 are of type a and of type b.)
In the second example, I'd say you're trying to give a new type to the get method. When you override a method in OCaml, the parameter and return types need to be the same as in the parent class.
The error message seems unfortunate. My guess is that the compiler is believing you that type b is another name for type a.
One of OCaml's strengths is that it will infer types. If you leave off the : b for the parameter of get in class b, you get the following error instead:
This expression has type a. It has no method foo
This is a little more helpful, in that it shows (I think) that you're required to have type a for the parameter.
Side comment (forgive me): if you come to the OO part of OCaml from a mainstream OO language, it might strike you as strange. But if you learn the FP part of OCaml first, you might wonder why all the mainstream OO languages get so many things wrong :-). (Granted, everything is tradeoffs and there is no one right way to structure computation. But OCaml's OO subsystem is doing something pretty impressive.)