This is just a simple program I wrote to try to get a better understanding about modules. I'm trying to call the toS function with Id("a",Int) but it seems like I can write a type ast like this. What may be the problem?
module Typ =
struct
type typ = Int | Bool
end
module Symbol =
struct
type t = string
end
module Ast =
struct
type ast = Const of int * Typ.typ | Id of Symbol.t * Typ.typ
let rec toS ast = match ast with Id(a,b) -> "a"
|_->"b"
end
Ast.toS Id("a",Int)
You are getting an error because you did not surround your type constructor with parens in the function application. However, you must also reference type constructors by fully qualified names outside the module they're defined in. I.e.
Ast.toS (Ast.Id("a",Typ.Int))
Alternatively, you can open the modules. But this is considered bad practice. I.e.
open Id
open Typ
Ast.toS (Id("a",Int))
Related
In OCaml, to bring another module in scope you can use open. But what about code like this:
module A = struct
include B.C
module D = B.E
end
Does this create an entirely new module called A that has nothing to do with the modules created by B? Or are the types in B equivalent to this new structure and can a type in A.t can be used interchangeably with a type in B.C.t for example?
Especially, comparing to Rust I believe this is very different from writing something like
pub mod a {
pub use b::c::*;
pub use b::e as d;
}
Yes, module A = struct include B.C end creates an entirely new module and exports all definitions from B.C. All abstract types and data types that are imported from B.C are explicitly related to that module.
In other words, suppose you have
module Inner = struct
type imp = Foo
type t = int
end
so when we import Inner we can access the Inner definitions,
module A = struct
include Inner
let x : imp = Foo
let 1 : t = 1
end
and the Foo constructor in A belongs to the same type as the Foo constructor in the Inner module so that the following typechecks,
A.x = Inner.Foo
In other words, include is not a mere copy-paste, but something like this,
module A = struct
(* include Inner expands to *)
type imp = Inner.imp = Foo
type t = Inner.t = int
end
This operation of preserving type equalities is formally called strengthening and always applied when OCaml infers module type. In other words, the type system never forgets the type sharing constraints and the only way to remove them is to explicitly specify the module type that doesn't expose the sharing constraints (or use the module type of construct, see below).
For example, if we will define a module type
module type S = sig
type imp = Foo
type t = int
end
then
module A = struct
include (Inner : S)
end
will generate a new type foo, so A.Foo = Inner.Foo will no longer type check. The same could be achieved with the module type of construct that explicitly disables module type strengthening,
module A = struct
include (Inner : module type of Inner)
end
will again produce A.Foo that is distinct from Inner.Foo. Note that type t will be still compatible in all implementation as it is a manifest type and A.t is equal to Inner.t not via a sharing constraint but since both are equal to int.
Now, you might probably have the question, what is the difference between,
module A = Inner
and
module A = struct include Inner end
The answer is simple. Semantically they are equivalent. Moreover, the former is not a module alias as you might think. Both are module definitions. And both will define a new module A with exactly the same module type.
A module alias is a feature that exists on the (module) type level, i.e., in the signatures, e.g.,
module Main : sig
module A = Inner (* now this is the module alias *)
end = struct
module A = Inner
end
So what the module alias is saying, on the module level, is that A is not only has the same type as Inner but it is exactly the Inner module. Which opens to the compiler and toolchain a few opportunities. For example, the compiler may eschew module copying as well as enable module packing.
But all this has nothing to do with the observed semantics and especially with the typing. If we will forget about the explicit equality (that is again used mostly for more optimal module packing, e.g., in dune) then the following definition of the module A
module Main = struct
module A = Inner
end
is exactly the same as the above that was using the module aliasing. Anything that was typed with the previous definition will be typed with the new definition (modulo module type aliases). It is as strong. And the following is as strong,
module Main = struct
module A = struct include Inner end
end
and even the following,
module Main : sig
module A : sig
type imp = Impl.imp = Foo
type t = Impl.t = int
end
end = struct
module A = Impl
end
So when you define the structure of a module, it's possible to extend another module off of it:
module Base = struct
type t = Name of string
end
module Child = struct
include Base
end
Child.Name "test"
(* - : Child.t = Child.Name "test" *)
However, when working with recursive modules using recursive signatures, I run into issues when I try to extend a module:
module rec Base : sig
type t = | Name of string
end = Base
and Child : sig
include Base
end = Child
When I do this, I get an error saying:
Error: Unbound module type Base
Can you not extend modules when working with this recursive module trick? Am I misunderstanding something or doing something wrong?
It seems to me your problem is that Base is a module, not a module type. When including in a sig ... end construct you need a type. When including in a struct ... end construct you need a module. That's why the first example works and the second one doesn't.
If I change Base to module type of Base I get this error:
Error: Illegal recursive module reference
So I suspect this particular (somewhat strange) type of recursive definition isn't supported.
If you define the module type separately, you can make it work:
module type BASE = sig type t = Name of string end
module rec Base : BASE = Base
and Child : sig
include BASE
end = Child
Jeffrey Scofield already gave a good answer. I'd just like to add that include is just syntactic sugar. So if it is include which is causing you trouble, a solution might be to expand it. In the first of your examples that would lead to
module Base = struct
type t = Name of string
end
module Child = struct
type t = Name of string
end
Apparently, your examples are simplified versions of what you really want to do. As shown, there is no need to use rec at all. So I can only guess how much recursion you really need. According to Jeffrey Scofield's answer, the combination of rec and include is problematic. Possibly, getting rid of include suffices for you.
I want to write a function that, given a non-negative integer n, returns the power set of {1,...,n}. So I want to use the Set.S module as found here. But I can't seem to import it. When I run the following code:
open Set.S
let rec power_set n =
if n = 0 then add empty empty else union (iter (add n s) power_set (n-1)) (power_set (n-1));;
let print_set s = SS.iter print_endline s;;
print_set (power_set 2)
I get the error:
File "countTopologies.ml", line 1, characters 5-10:
Error: Unbound module Set.S
Maybe I just don't have the Set.S module installed on my computer? (I've only done the bare bones needed to install OCaml). If this is the case, how would I get it?
The Set.S is a module type, not a module. You can open only modules. In fact, the module Set contains three elements:
the module type OrderedType that denotes the type of modules that implement ordered types;
the module type S that denotes the type of modules that implement Set data structures;
the functor Make that takes a module of type OrderedType and returns a module of type S.
To get a set module you need to create it using the Set.Make functor. The functor has one parameter - the module for the set elements. In modern OCaml (4.08+) you can create a set module for integers as easy as,
module Ints = Set.Make(Int)
and then you can use like this,
let numbers = Ints.of_list [1;2;3]
assert (Ints.mem 2 numbers)
For older versions of OCaml, which doesn't provide the Int module, or for non-standard (custom) types, you need to define your own module that implements the OrderedType interface, e.g.,
module Int = struct
type t = int
(* use Pervasives compare *)
let compare = compare
end
module Ints = Set.Make(Int)
You can also use non-standard libraries, like Janestreet's Core library, which provide sets out of box. The Core library has an Int module that is already charged with sets, maps, hashtables, so it can be accessed without any functors:
open Core.Std
let nil = Int.Set.empty
Or, in the modern (2018-2019) version of Janestreet Core or Base libraries, you can use polymorphic sets/maps, which require you to specify the module for keys only when a new set or map is created, e.g., like this
open Base (* or Core, or Core_kernel *)
let nil = Set.empty (module Int)
let one = Set.add nil 1
let two = Set.singleton (module Int) 2
You have to Make a set module from the Set functor.
module SI = Set.Make(struct type t = int let compare = compare end)
Then you can have a set of ints:
# let myset = SI.add 3 SI.empty;;
val myset : SI.t = <abstr>
# SI.elements myset;;
- : SI.elt list = [3]
I'm curious to understand why this error happens and which is the best way to get around it.
I have a couple of files types.ml and types.mli which define a variant type value that can be of many different builtin OCaml types (float, int, list, map, set, etc..).
Since I have to use the std-lib over this variant type I needed to concretize the Set module through the functor to be able to use sets of value type by defining the ValueSet module.
The final .ml file is something like:
module rec I :
sig
type value =
Nil
| Int of int
| Float of float
| Complex of Complex.t
| String of string
| List of (value list) ref
| Array of value array
| Map of (value, value) Hashtbl.t
| Set of ValueSet.t ref
| Stack of value Stack.t
...
type t = value
val compare : t -> t -> int
end
= struct
(* same variant type *)
and string_value v =
match v with
(* other cases *)
| Set l -> sprintf "{%s} : set" (ValueSet.fold (fun i v -> v^(string_value i)^" ") !l "")
end
and OrderedValue :
sig
type t = I.value
val compare : t -> t -> int
end
= struct
type t = I.value
let compare = Pervasives.compare
end
and ValueSet : Set.S with type elt = I.value = Set.Make(I)
As you can see I had to define the ValueSet module from the functor to be able to use that datatype. The problem occurs when I want to use that module inside the declaration of I. So that I obtain the following error:
Error: Cannot safely evaluate the definition of the recursively-defined module I
Why does this happen? Which is a good way to solve it? And just to know, is my approach to what I'm trying to do correct? Apart from that it works as intended (I'm able to use the ValueSet type with my operations in other modules, but I have to comment the involved line in types.ml to pass compilation phase).
I tried to remove all the superfluous code and reduce the code to essential needed to investigate this error.. if it's not enought just ask :)
EDIT: according to OCaml reference we have that
Currently, the compiler requires that all dependency cycles between the recursively-defined module identifiers go through at least one “safe” module. A module is “safe” if all value definitions that it contains have function types typexpr1 -> typexpr2.
This is everything I found so far, but I don't get the exact meaning..
Thank in advance
After fixing the obvious errors, your example does compile (with OCaml 3.10, but I think this hasn't changed since recursive modules were introduced in 3.07). Hopefully my explanations below will help you find what, amongst the definitions you left out, caused your code to be rejected.
Here is some example code that is accepted:
module rec Value : sig
type t =
Nil
| Set of ValueSet.t
val compare : t -> t -> int
val nil : t
(*val f_empty : unit -> t*)
end
= struct
type t =
Nil
| Set of ValueSet.t
let compare = Pervasives.compare
let nil = Nil
(*let f_empty () = Set ValueSet.empty*)
end
and ValueSet : Set.S with type elt = Value.t = Set.Make(Value)
At the expression level, the module Value has no dependency on ValueSet. Therefore the compiler generates the code to initialize Value before the code to initialize Value, and all goes well.
Now try commenting out the definition of f_empty.
File "simple.ml", line 11, characters 2-200:
Cannot safely evaluate the definition of the recursively-defined module Value
Now Value does depend on ValueSet, and ValueSet always depends on Value because of the compare function. So they are mutually recursive, and the “safe module” condition must apply.
Currently, the compiler requires that all dependency cycles between the
recursively-defined module identifiers go through at least one "safe" module. A
module is "safe" if all value definitions that it contains have function types
typexpr_1 -> typexpr_2.
Here, ValueSet isn't safe because of ValueSet.empty, and Value isn't safe because of nil.
The reason to the “safe module” condition is the chosen implementation technique for recursive module:
Evaluation of a recursive module definition proceeds
by building initial values for the safe modules involved, binding all
(functional) values to fun _ -> raise Undefined_recursive_module. The defining
module expressions are then evaluated, and the initial values for the safe
modules are replaced by the values thus computed.
If you comment out the declaration of nil in the signature of Value, you can leave the definition and declaration of f_empty. That's because Value is now a safe module: it contains only functions. It's ok to leave the definition of nil in the implementation: the implementation of Value is not a safe module, but Value itself (which is its implementation coerced to a signature) is safe.
I'm really not sure what kind of syntax you're using in the signature that allows let ... I'm going to assume it was a mistake while reducing the code for us. You also don't need that OrderedType definition, possibly another fiddling error for us, since you don't use it in parameterisation of the Set module.
Aside from that, I have no problem running the following in the toplevel. Since this works pretty directly, I am unsure how you're getting that error.
module rec Value :
sig
type t =
| Nil
| Int of int
| Float of float
| String of string
| Set of ValueSet.t
val compare : t -> t -> int
val to_string : t -> string
end = struct
type t =
| Nil
| Int of int
| Float of float
| String of string
| Set of ValueSet.t
let compare = Pervasives.compare
let rec to_string = function
| Nil -> ""
| Int x -> string_of_int x
| Float x -> string_of_float x
| String x -> x
| Set l ->
Printf.sprintf "{%s} : set"
(ValueSet.fold (fun i v -> v^(to_string i)^" ") l "")
end
and ValueSet : Set.S with type elt = Value.t = Set.Make (Value)
I'm quite stuck with the following functor problem in OCaml. I paste some of the code just to let you understand. Basically
I defined these two modules in pctl.ml:
module type ProbPA = sig
include Hashtbl.HashedType
val next: t -> (t * float) list
val print: t -> float -> unit
end
module type M = sig
type s
val set_error: float -> unit
val check: s -> formula -> bool
val check_path: s -> path_formula -> float
val check_suite: s -> suite -> unit
end
and the following functor:
module Make(P: ProbPA): (M with type s = P.t) = struct
type s = P.t
(* implementation *)
end
Then to actually use these modules I defined a new module directly in a file called prism.ml:
type state = value array
type t = state
type value =
| VBOOL of bool
| VINT of int
| VFLOAT of float
| VUNSET
(* all the functions required *)
From a third source (formulas.ml) I used the functor with Prism module:
module PrismPctl = Pctl.Make(Prism)
open PrismPctl
And finally from main.ml
open Formulas.PrismPctl
(* code to prepare the object *)
PrismPctl.check_suite s.sys_state suite (* error here *)
and compiles gives the following error
Error: This expression has type Prism.state = Prism.value array
but an expression was expected of type Formulas.PrismPctl.s
From what I can understand there a sort of bad aliasing of the names, they are the same (since value array is the type defined as t and it's used M with type s = P.t in the functor) but the type checker doesn't consider them the same.
I really don't understand where is the problem, can anyone help me?
Thanks in advance
(You post non-compilable code. That's a bad idea because it may make it harder for people to help you, and because reducing your problem down to a simple example is sometimes enough to solve it. But I think I see your difficulty anyway.)
Inside formulas.ml, Ocaml can see that PrismPctl.s = Pctl.Make(Prism).t = Prism.t; the first equality is from the definition of PrismPctl, and the second equality is from the signature of Pctl.Make (specifically the with type s = P.t bit).
If you don't write an mli file for Formulas, your code should compile. So the problem must be that the .mli file you wrote doesn't mention the right equality. You don't show your .mli files (you should, they're part of the problem), but presumably you wrote
module PrismPctl : Pctl.M
That's not enough: when the compiler compiles main.ml, it won't know anything about PrismPctl that's not specified in formulas.mli. You need to specify either
module PrismPctl : Pctl.M with type s = Prism.t
or, assuming you included with type s = P.t in the signature of Make in pctl.mli
module PrismPctl : Pctl.M with type s = Pctl.Make(Prism).s
This is a problem I ran into as well when learning more about these. When you create the functor you expose the signature of the functor, in this case M. It contains an abstract type s, parameterized by the functor, and anything more specific is not exposed to the outside. Thus, accessing any record element of s (as in sys_state) will result in a type error, as you've encountered.
The rest looks alright. It is definitely hard to get into using functors properly, but remember that you can only manipulate instances of the type parameterized by the functor through the interface/signature being exposed by the functor.