I have problems defining the type of a module that is returned by a functor. Could anyone solve this?
module type ANIMALTYPE = sig
val age : unit -> int
end
module type SHIPGENERATOR = sig
val age : unit -> int
(* Another possibility: include ANIMALTYPE *)
val hello : string
end
module RabbitModule : ANIMALTYPE = struct
let age () = 10
end
module Make_ShipGenerator (A : ANIMALTYPE) = struct
let age = A.age
let hello = "world"
end
let get_shipgenerator race = match race with
| Rabbit -> let module M = (Make_ShipGenerator (RabbitModule))
in (module M : SHIPGENERATOR)
Edit: Added hello to Make_ShipGenerator.
Edit 2: Added module type SHIPGENERATOR, which will include those parts needed from ANIMALTYPE.
Well, it is ANIMALTYPE, what else?
let module M = (Make_ShipGenerator (RabbitModule))
in (module M : ANIMALTYPE);;
Related
I'm studying functors, and I was trying to receive a Module.t as argument where Module is the result of a functor call SomeFunctor(sig type t = int end) but I receive Unbound type constructor FooInt.t
Here is the code
module type Foo_S = sig
type t
end
module type Foo = sig
type t
val id : t -> t
end
module FooExtend(Arg : Foo_S) : (Foo with type t := Arg.t) = struct
let id a = a
end
module FooInt = FooExtend(Int)
module FooString = FooExtend(String)
let () =
assert (FooInt.id 1 = 1);
assert (FooString.id "x" = "x")
module FooSimple = struct type t = int end
let foo (x : FooInt.t) = (* This doens't compile: Unbound type constructor FooInt.t *)
FooInt.id x
let foo' (x : FooSimple.t) = (* This works fine *)
FooInt.id x
Two changes are needed, 1) type t needs to be defined in the module, and 2) don't use destructive substitution:
module FooExtend(Arg : Foo_S) : (Foo with type t = Arg.t) = struct
type t = Arg.t
let id a = a
end
The problem is that destructive substitution (type t := Arg.t) replaces every occurrence of t with Arg.t. Instead you want to specify type equality, using a "sharing constraint" (type t = Arg.t).
Notice the difference in the resulting module signature between the two:
module FooExtend(Arg : Foo_S) : (Foo with type t := Arg.t) = struct
type t = Arg.t
let id a = a
end
module FooExtend : functor (Arg : Foo_S) -> sig
val id : Arg.t -> Arg.t
end
module FooExtend(Arg : Foo_S) : (Foo with type t = Arg.t) = struct
type t = Arg.t
let id a = a
end
module FooExtend : functor (Arg : Foo_S) -> sig
type t = Arg.t
val id : t -> t
end
I have a module in OCaml that is parameterized by another module, which represents a data structure (H = Hashtable, M = Map, L = LossyMap). I would now like to let this data structure be selected via the command line.
The way I create the main processing module is:
module HashSampler = MakeSampler(HashtableMatrix)
module MapSampler = MakeSampler(MapMatrix)
etc.
Unfortunately, the code that multiplexes between these is ugly:
match representation with
| "Hashtable" ->
let matrix = HashSampler.create () in
HashSampler.process_file matrix file
| "Map" ->
let matrix = MapSampler.create () in
MapSampler.process_file matrix file
Is there a better way of doing this that somehow prevents code duplication?
You can use first class modules. Here's some example code that shows one possibility.
module type Sampler = sig
type t
val create : unit -> t
val process_file : t -> string -> unit
end
module HashSampler : Sampler = struct
type t = unit
let create () = ()
let process_file () file = ()
end
module MapSampler : Sampler = struct
type t = unit
let create () = ()
let process_file () file = ()
end
let choose_sampler : string -> (module Sampler) = function
| "Hashtable" -> (module HashSampler)
| "Map" -> (module MapSampler)
let process representation file =
let (module M) = choose_sampler representation in
let matrix = M.create () in M.process_file matrix file
I try to understand a strange behaviour of some functions of a module that rely on a variable of this module masked by the signature of this module. I would like to print this variable at some points of the program, but since it is masked, I do not known how to access it.
Moreover, this module is part of a big project that I do not want to modify and recompile myself.
Is it possible to access this variable for debugging purposes ? Even doing temporarily dirty things ?
EDIT: here some representative code
module type S = sig val f : unit -> unit end
module M : S = struct let x = ref 0 let f () = Format.printf "%d#." !x; incr x end
How to access M.x ?
Of course you can!
First, you can just hide the signature for a while :
module type S = sig val f : unit -> unit end
module M (* : S *) = struct
let x = ref 0
let f () = Format.printf "%d#." !x; incr x
end
Or you can show x in the signature :
module type S = sig
val x : int ref
val f : unit -> unit
end
module M : S = struct
let x = ref 0
let f () = Format.printf "%d#." !x; incr x
end
As you prefer. In both cases, M.x will be available outside the module.
You can even define a function print_x like this :
module type S = sig
val print_x : unit -> unit
val f : unit -> unit
end
module M : S = struct
let x = ref 0
let print_x () = Format.printf "%d#." !x
let f () = Format.printf "%d#." !x; incr x
end
and use M.print_x () wherever you want.
Suppose I have these signatures :
module type CharS = sig
type c
type t = BoW | C of c | EoW
val compare : t -> t -> int
val print : Format.formatter -> t -> unit
end
module type GraphemS = sig
type c
type t
val compare : t -> t -> int
val print : Format.formatter -> t -> unit
end
And these two functors :
module MakeDiGraphem (C : CharS) : GraphemS with type c = C.t = struct
type c = C.t
type t = c * c
let compare (cb1, ce1) (cb2, ce2) =
let r1 = C.compare cb1 cb2 in
if r1 = 0 then
C.compare ce1 ce2
else r1
let print fmt (cb, ce) =
Format.fprintf fmt "#[%a%a#]#," C.print cb C.print ce
end
module MakeMonoGraphem (C : CharS) : GraphemS with type c = C.t = struct
type c = C.t
type t = c
let compare c1 c2 = C.compare c1 c2
let print fmt c =
Format.fprintf fmt "#[%a#]#," C.print c
end
Now, I'd like to have a functor which would allow me to create a module of type GraphemS with either the first functor or the second one. What I did is this :
module type SizeS = sig
type t = int
val param : int
end
module MakeGraphem (C : CharS) (I : SizeS) : GraphemS with type c = C.t = struct
module MonoGraphem = MakeMonoGraphem(C)
module DiGraphem = MakeDiGraphem(C)
let select_graphem =
if I.param = 1 then
(module MonoGraphem : GraphemS)
else
(module DiGraphem : GraphemS)
include (val select_graphem)
end
But sadly I got :
Error: This expression creates fresh types.
It is not allowed inside applicative functors.
My question is, then, is it possible to do what I want to do and what does this error means ?
Basically, you are not allowed to do first-class calculations in an applicative functor application include. Basically, the typing system has no guarantee that I.param is a constant so it can't ensure that the functor will always return the same type. An applicative functor (the default in OCaml) has to always return the same type for the same expression (in a sense, it's pure).
If you are on OCaml 4.02 or more, you can declare your functor as generative through a unit argument:
module MakeGraphem (C : CharS) (I : SizeS) () :
GraphemS with type c = C.t = struct
My favorite way of doing the trick would be to get the functor to apply as an argument instead of I.
I'm new to OCaml, and trying to learn about functors. So far, I have the following:
utop # module type Foo = sig
type t = {
foo : int;
bar : int;
}
val create : int -> int -> t
val get : t -> int
end;;
utop # module FooImpl = struct
type t = {
foo : int;
bar : int;
}
let create x y = {
foo = x;
bar = y;
}
let get w = w.foo
end;;
Now I'll try to define my functor, which will operate on modules of type Foo and replace the get function.
utop # module Functor (F : Foo) : Foo with type t := F.t = struct
let create = F.create
let get w = w.bar
end;;
Error: Unbound record field bar
It doesn't know about the type of the record. I'll try defining it:
utop # module Functor (F : Foo) : Foo with type t := F.t = struct
type t = {
foo : int;
bar : int;
}
let create = F.create
let get w = w.bar
end;;
Error: Signature mismatch: ... Values do not match:
val get : t -> int
is not included in
val get : F.t -> int
So OCaml doesn't know that t and F.t are actually the same type. So I'll try saying that:
utop # module Functor (F : Foo) : Foo with type t := F.t = struct
type t = F.t
let create = F.create
let get w = w.bar
end;;
Error: Unbound record field bar
What am I doing incorrectly?
Field names belong to a scope of a module where they are defined. For example, if you define a record in module Foo
module Foo = struct
type t = { bar : int; baz : int; quz : int }
end
Then in order to access this fields outside of the module Foo you need to use a fully qualified name, e.g.,
let bar_of_foo x = x.Foo.bar
In pattern matching field names may be also qualified, this allows to write the above function as follows:
let bar_of_foo {Foo.bar} = bar
You need to qualify only one name, so this syntax is useful, when you need to access several fields at once:
let sum_of_foo {Foo.bar; baz; quz} = bar + baz + quz
Finally, you can open module to bring the record names to the current scope. You can use local open syntax Foo.(expr) to localize the impact of opening:
let bar_of_foo x = Foo.(x.bar)
In your example fields are defined in module F that is a parameter to a functor Functor. So, you need to use one of the above methods to access it fields, e.g.,
module Functor (F : Foo) : Foo with type t := F.t = struct
open F
let create = F.create
let get w = w.bar
end
Your first attempt at defining Functor works for me if I define get like this:
let get w = w.F.bar
Here's my full session:
# module type Foo = sig (... ELIDED...) end;;
module type Foo =
sig
type t = { foo : int; bar : int; }
val create : int -> int -> t
val get : t -> int
end
# module FooImpl = struct (...ELIDED...) end;;
module FooImpl :
sig
type t = { foo : int; bar : int; }
val create : int -> int -> t
val get : t -> int
end
# module Functor (F: Foo) : Foo with type t := F.t = struct
let create = F.create
let get w = w.F.bar
end;;
module Functor :
functor (F : Foo) ->
sig val create : int -> int -> F.t val get : F.t -> int end
# module F2 = Functor(FooImpl);;
module F2 :
sig val create : int -> int -> FooImpl.t val get : FooImpl.t -> int end
# let c1 = FooImpl.create 8 9;;
val c1 : FooImpl.t = {FooImpl.foo = 8; bar = 9}
# FooImpl.get c1;;
- : int = 8
# let c2 = F2.create 8 9;;
val c2 : FooImpl.t = {FooImpl.foo = 8; bar = 9}
# F2.get c2;;
- : int = 9