Ocaml - Forward Declaration (Classes) - ocaml

I need to have two classes refering to each other. Is there any way in Ocaml to make Forward Declaration of one of them?
(I don't think it's possible as with easier stuff with word and).
Or maybe it is possible, but different way than how i tried?

Ocaml doesn't have anything like forward declarations (i.e. a promise that something will be defined eventually), but it has recursive definitions (i.e. a block of things that are declared and then immediately defined in terms of each other). Recursive definitions are possible between expressions, types, classes, and modules (and more); mutually recursive modules allow mixed sets of objects to be defined recursively.
You can solve your problem using a recursive definition with the keyword and:
class foo(x : bar) = object
method f () = x#h ()
method g () = 0
end
and bar(x : foo) = object
method h () = x#g()
end

Or you could use parameterized classes. Following the previous example you have:
class ['bar] foo (x : 'bar) =
object
method f () = x#h ()
method g () = 0
end
class ['foo] bar (x : 'foo) =
object
method h () = x#g()
end
The inferred interface is:
class ['a] foo : 'a ->
object
constraint 'a = < h : unit -> 'b; .. >
method f : unit -> 'b
method g : unit -> int
end
class ['a] bar : 'a ->
object
constraint 'a = < g : unit -> 'b; .. >
method h : unit -> 'b
end

Related

How to Define Something that Acts as a Dictionary of Unique Functions in F#?

It is my understanding that a Dictionary's elements must all be the same (ie: unit -> unit)
I need a way to add functions to an object, similar to a Dictionary, but my problem is that the functions have different Types. The only thing I can know for sure is that added functions will always follow a pattern of int -> 'T where 'T could be any Type. All functions in the object could be made to inherit from a shared type if needed. Here is a non-functioning example of how it would be used.
let myFunctions = Dictionary<int,int -> unit>()
let exampleFunction0 (x : int) : int = x + 1
let exampleFunction1 (x : int) : byte = (byte)x
let exampleFunction2 (x : int) : string[] = Array.create<string> 1 "test"
myFunctions.Add(0, exampleFunction0)
myFunctions.Add(1, exampleFunction1)
myFunctions.Add(2, exampleFunction2)
let randomNumber = System.Random().Next(3)
let result x = myFunctions.Item(randomNumber) x
It is important to note that which one of the functions that gets called is random and I cannot know it. The purpose of the dictionary is to hold the functions that will be called randomly. As in the examples, the results are not the same as I need the results to be different for each function. x will always be the same, but the result of the function will not.
The code will be in a library to be reused, so functions may be added that I will never see.
You need to unify the output types to make this work.
If all the types are known you should use a Discriminated Union.
type ReturnValues =
| Case0 of int
| Case1 of byte
| Case2 of string[]
let myFunctions = Dictionary<int,int -> ReturnValues>()
let exampleFunction0 (x : int) = x + 1 |> Case0
let exampleFunction1 (x : int) = (byte)x |> Case1
let exampleFunction2 (x : int) = Array.create<string> 1 "test" |> Case2
myFunctions.Add(0, exampleFunction0)
myFunctions.Add(1, exampleFunction1)
myFunctions.Add(2, exampleFunction2)
let randomNumber = System.Random().Next(3)
let result x : ReturnValues = myFunctions.Item(randomNumber) x
If you don't know all the types you can make all the return types obj (Dictionary<int,int -> obj>) using the box function or you can make all the return types implement a common interface.
What has ultimately solved the problem for me is to package together the Type and Object. This package is what the functions that will be added to the dictionary must return. This way there is a standard way for new types to be added after compilation.
open System.Collections.Generic
open System
// a package that can hold an object and its type
type package(x, y) =
member this.x : Type = x
member this.y : Object = y
//empty class for testing
type testClass() = class end
//custom types for testing
type fiy(x) =
member this.Value : string = x
type foe(x) =
member this.Value : testClass = x
//functions for testing
let func0 (x: int) : package = package(typeof<int>, x)
let func1 (x: int) : package = package(typeof<fiy>, fiy("potato"))
let func2 (x: int) : package = package(typeof<foe>, foe(testClass()))
let myFunctions = Dictionary<int, (int -> package)>()
//example use of adding a function
myFunctions.Add(0, (func0))
myFunctions.Add(1, (func1))
myFunctions.Add(2, (func2))
//pick a random number to test with; as we will have no idea which function will be ran
let randomNumber = System.Random().Next(3)
let pickedFunction x : package = (myFunctions.Item(randomNumber) x)
let ranFunction = pickedFunction 5 //just some filler number to test with
printfn "The type of the ranFunction is: %s" (ranFunction.x.ToString())

Certain AST nodes not possible in Parsetree.signature (mli files)

I'm writing a tool that generates ml stubs from mli files. I have the meaningful mappings complete (var f : int -> float to let f _ = 0.), but I'm having a little trouble reasoning about the AST nodes for classes and modules, specifically the Pmty_* and Pcty_* nodes. These two types of nodes (given the type hierarchy) seem to most most associated with mli files. Some of the trivial members--which appear in -dparsetrees of mli files (like Pmty_ident and Pcty_constr) have obvious mappings to nodes most associated with ml files (again by the hierarchy of the signature and structure types, in the aforementioned example to Pmod_ident and Pcl_constr). However, some of the nodes don't have an obvious parallel. Specifically, I'm having trouble reasoning about:
Pmty_with and Pmty_typeof - it seems like these two can never be parsed from a valid mli file; they only occur in a structure context that has a module_type as one of its members (I've checked my suspicions against all of OCaml's parser test files)
Pcty_signature - it seems like the only case this can occur is within a Psig_class_type (which I already directly map to Pstr_class_type); I against the OCaml test files and found a Pcty_signature only in this location, but are there other valid locations for it in an mli that I am missing?
Pcty_arrow - there are no test files containing this, so I can't be sure where it is valid, but my intuition says this also goes in a class_type context within a structure only (or within one of the other Pcty_*, in which case its conversion would be handled as a child by that node's mapping from Pcty_* to Pcl_*); is this incorrect?
I'm fairly deep into this and don't completely understand what's going on with all of these advanced language features and the AST nodes representing them, so here's an attempt at a simpler explanation of my questions:
Relevant types extracted from Parsetree:
type module_type_desc =
(* .. snip .. *)
| Pmty_with of module_type * with_constraint list
(* MT with ... *)
| Pmty_typeof of module_expr
(* module type of ME *)
type class_type_desc =
(* .. snip .. *)
| Pcty_signature of class_signature
(* object ... end *)
| Pcty_arrow of arg_label * core_type * class_type
(* T -> CT Simple
~l:T -> CT Labelled l
?l:T -> CT Optional l
*)
I believe that Pmty_with and Pmty_typeof can only occur in ml files (and not mli files). Is this assumption correct?
Can Pcty_signature occur as a node that isn't the child of a Psig_class_type?
Can a Pcty_arrow occur in a valid mli file? Where? As a child of what?
As I mentioned before, I'm fairly confident of my handling of every besides these two (modules and classes). In case the above isn't clear, here's an annotated snippet of the code that transforms Parsetree.signature -> Parsetree.structure with all of the non-module/class stuff removed for brevity:
(* Parsetree.signature -> Parsetree.structure *)
let rec stub signature_items =
(* Handles the module_type_desc *)
let rec stub_module_type module_type =
match module_type with
| { pmty_desc = type_; pmty_attributes = attrs; _ } ->
let expr =
match type_ with
| Pmty_ident ident -> Pmod_ident ident
| Pmty_signature signatures -> Pmod_structure (stub signatures)
| Pmty_functor (name, a, b) -> Pmod_functor (name, a, (stub_module_type b))
(* XXX: unclear if these two can occur in an mli *)
(* | Pmty_with (type_, constraints) -> _ TODO *)
(* | Pmty_typeof type_ -> _ TODO *)
| Pmty_extension ext -> Pmod_extension ext
| Pmty_alias name -> Pmod_ident name
in
make_module_expr expr attrs
in
(* The next three functions handles the module_type for single and multiple (rec) modules *)
let stub_module_decl module_decl =
match module_decl with
| { pmd_name = name; pmd_type = type_; pmd_attributes = attrs; _ } ->
make_module_binding name (stub_module_type type_) attrs
in
let stub_module module_ = Pstr_module (stub_module_decl module_)
and stub_modules modules = Pstr_recmodule (List.map stub_module_decl modules)
and stub_include include_ =
match include_ with
| { pincl_mod = module_type; pincl_attributes = attrs; _ } ->
Pstr_include (make_include_decl (stub_module_type module_type) attrs)
in
(* Handles classes (class_type) *)
let stub_classes classes =
(* Handles class_type_desc *)
let stub_class_descr descr =
let rec stub_class class_ =
let stub_class_type type_ =
match type_ with
| Pcty_constr (ident, types) -> Pcl_constr (ident, types)
| Pcty_signature class_ -> (* XXX: Is my below assumption true? *)
failwith "should be covered by Psig_class_type -> Pstr_class_type"
(* XXX: do we ever need to handle Pcty_arrow for mli files? *)
(* | Pcty_arrow (label, a, b) -> _ *)
| Pcty_extension ext -> Pcl_extension ext
| Pcty_open (override, ident, class_) ->
Pcl_open (override, ident, (stub_class class_))
in
match class_ with
| { pcty_desc = type_; pcty_attributes = attrs; _ } ->
make_class_expr (stub_class_type type_) attrs
in
match descr with
| { pci_virt = virt; pci_params = params; pci_name = name;
pci_expr = class_; pci_attributes = attrs } ->
make_class_decl virt params name (stub_class class_) attrs
in
Pstr_class (List.map stub_class_descr classes)
in
let transform_signature signature_item =
match signature_item with
| { psig_desc = signature; _ } ->
let desc =
match signature with
(* ... clip non-module/class stuff ... *)
| Psig_module module_ -> stub_module module_
| Psig_recmodule modules -> stub_modules modules
| Psig_include include_ -> stub_include include_
| Psig_class classes -> stub_classes classes
| Psig_class_type classes -> Pstr_class_type classes
in
make_str desc
in
List.map transform_signature signature_items
Unfortunately the module/class stuff is rather complex logic, so trimmed down there's still a lot. There are a ton of helps for creating the *_desc wrappers that encapsulate location in the file, attributes, etc., but those shouldn't be key to understanding how I'm handling modules and classes. But just for clarity, here are the types of all of the helpers:
val make_str : Parsetree.structure_item_desc -> Parsetree.structure_item
val make_module_expr :
Parsetree.module_expr_desc -> Parsetree.attributes -> Parsetree.module_expr
val make_module_binding :
string Asttypes.loc ->
Parsetree.module_expr -> Parsetree.attributes -> Parsetree.module_binding
val make_include_decl :
'a -> Parsetree.attributes -> 'a Parsetree.include_infos
val make_class_decl :
Asttypes.virtual_flag ->
(Parsetree.core_type * Asttypes.variance) list ->
string Asttypes.loc ->
'a -> Parsetree.attributes -> 'a Parsetree.class_infos
val make_class_expr :
Parsetree.class_expr_desc -> Parsetree.attributes -> Parsetree.class_expr
Relevant docs:
parsetree.ml (better than docs, because of some comments)
Edit: As an aside, besides reading documentation on these features (which didn't yield any AST patterns I didn't already know about), I recalled that the compiled can derive the interface from the implementation ocamlc -i. I traced down the variable in the compiler (it's called print_types) that's linked to this flag and found all of its uses, but it was not immediately apparent to me where at any of its uses code is called that derives the mli file (perhaps it is done progressively with the parse, since compiling produces a cmi?). If someone with more OCaml chops or more experience with the compiler could point me to where the mli file is derived, it may be easier to reverse engineer these module and class AST nodes.
Edit 2: I am also aware of How to auto-generate stubs from mli file?, however the answer there is "do it manually," which definitely conflicts with what I'm attempting! (The answerer also claims that such a tool would be trivial, but after pouring over these AST nodes for a while, I beg to differ!)
(I did not include the -dparsetree in my answer as it is heavy and not that interesting).
I believe that Pmty_with and Pmty_typeof can only occur in ml files (and not mli files). Is this assumption correct?
module M : module type of struct type t end with type t = int
As you can see from this valid mli file, this assumption isn't correct. .mli files require the same parser as .ml files do.
Can Pcty_signature occur as a node that isn't the child of a Psig_class_type?
class type c = object inherit object method x : int end end
Yes it can. Pcty_signature can occur anywhere a class type can occur. (note that there are two Pcty_signature here, one is the child of Pctf_inherit).
a Pcty_arrow occur in a valid mli file? Where? As a child of what?
class c' : int -> object method x : int end
Yes it can! And it can occur anywhere you'd indicate a class type.
Basically, you can consider that if a constructor can happen somewhere, then all the constructors of the same type can happen there too. Any type-related constructor can be in a .mli file (and non-type related constructors can happen too through the devious module type of).
If you have questions about where those are constructed, just take a look at parser.mly. Note that the same parser is used for the two file types.
This is a great game. Give me a list of AST Nodes, I'll write you a file that uses them all. :D
module K : module type of String
module M : Map.S with type key = K.t
class fakeref : K.t -> object
method get : K.t
method set : K.t -> unit
end
So, to summarize: Classes can take arguments, hence Pcty_arrow. Pcty_signature can also be the child of Psig_class, as shown above. The other two are standard module constructions that can absolutely appear in .mli files.
As for how ocamlc -i works ... well, it returns the signature inferred by the typechecker. There is no single point of access to this. You can read typing/HACKING.md if you want, but beware, the rabbit hole goes very deep. That being said, I do not think this will be all that helpful to achieve your goal.
My advice would be the following: all the nodes above are fairly easy to handle, except for with_type. This one is very hard, because it basically allows to compute in signatures. Just give up on that one for now.
Also, be aware that values, modules, module types, class and class types all have different namespaces. Pmty_ident x -> Pmod_ident x is not correct.

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

Can we pass functor as an argument to another functor?

I want to know if we can have a local module inside the module. This can be achieved if a functor can be passed as an argument to another functor. But I am not sure if we can do that.
My apologies if this is a vague question.
Thanks.
Yes, it is possible to define higher-order functors. Here is a simple example of a functor that applies its first argument to its second argument:
module App (F : functor (X: sig end) -> sig end) (X: sig end) = F (X)
This is however unrelated to the question of having local modules, which are very straightforward and do not require functors. The following example defines a submodule B that remains private to A:
module A : (sig val g : unit -> unit end) = struct
module B = struct
let f () = print_endline "Hello"
end
let g = B.f
end
let () = A.g () (* valid, prints Hello *)
let () = A.B.f () (* invalid *)

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.)