I'm trying to split the following recursive modules into separate compilation units. Specifically, I'd like B to be in its own b.ml, to be able to reuse it with other A's.
module type AT = sig
type b
type t = Foo of b | Bar
val f : t -> b list
end
module type BT = sig
type a
type t = { aaa: a list; bo: t option }
val g : t -> t list
end
module rec A : (AT with type b = B.t) = struct
type b = B.t
type t = Foo of b | Bar
let f = function Foo b -> [ b ] | Bar -> []
end
and B : (BT with type a = A.t) = struct
type a = A.t
type t = { aaa: a list; bo: t option }
let g b =
let ss = List.flatten (List.map A.f b.aaa) in
match b.bo with
| Some b' -> b' :: ss
| None -> ss
end
let a = A.Bar;;
let b = B.({ aaa = [a]; bo = None });;
let c = A.Foo b;;
let d = B.({ aaa = [a;c]; bo = Some b });;
I can't figure out how to split it across units.
The following sentence from Xavier Leroy's paper on the topic gives me hope that it's possible to encode using OCaml's module syntax: "the proposal does not support recursion between compilation units. The latter can however be encoded using separately-compiled functors, whose fix-point is taken later using the module rec construct".
I've played around with module rec but can't seem to find a way to make it type-check. The use of A's function f inside B's function g seems to cause the trouble.
(For the context, in the original code A.t is an instruction type, and B.t is a basic block type. Branch instructions reference blocks, and blocks contain lists of instructions. I'd like to reuse the basic block type and associated functions with different instruction sets.)
I think the paper is referring to something like this:
(* a.ml *)
module F (X : sig val x : 'a -> 'a end) =
struct
let y s = X.x s
end
(* b.ml *)
module F (Y : sig val y : 'a -> 'a end) =
struct
(* Can use Y.y s instead to get infinite loop. *)
let x s = Y.y |> ignore; s
end
(* c.ml *)
module rec A' : sig val y : 'a -> 'a end = A.F (B')
and B' : sig val x : 'a -> 'a end = B.F (A')
let () =
A'.y "hello" |> print_endline;
B'.x "world" |> print_endline
Running this (ocamlc a.ml b.ml c.ml && ./a.out) prints
hello
world
Obviously, the definitions of A and B I used are nonsense, but you should be able to substitute your own definitions into this pattern, as well as use named signatures instead of writing them out literally like I did.
The following seems to work, although it is rather ugly.
(* asig.mli *)
module type AT = sig
type b
type b' (* b = b' will be enforced externally *)
type t
val f : t -> b' list
end
(* bsig.mli *)
module type BT = sig
type a
type b' (* t = b' will be enforced externally *)
type t = { aaa: a list; bo: b' option }
val g : t -> b' list
end
(* b.ml *)
open Asig
module MakeB(A : AT) = struct
type a = A.t
type t = { aaa: a list; bo: A.b' option }
type b' = A.b'
let g b =
let ss = List.flatten (List.map A.f b.aaa) in
match b.bo with
| Some b' -> b' :: ss
| None -> ss
end
(* a.ml *)
open Asig
open Bsig
module type ASigFull = sig
type b
type b'
type t = Foo of b | Bar
val f : t -> b' list
end
module type BMAKER = functor (A : AT) -> (BT with type a = A.t
and type b' = A.b')
module MakeAB(MakeB : BMAKER) = struct
module rec B1 : (BT with type a = A1.t
and type b' = A1.b') = MakeB(A1)
and A1 : (ASigFull with type b = B1.t
and type b' = B1.t) = struct
type b = B1.t
type b' = b
type t = Foo of b | Bar
let f = function Foo b -> [ b ] | Bar -> []
end
module A = (A1 : ASigFull with type t = A1.t and type b = B1.t and type b' := B1.t)
module B = (B1 : BT with type t = B1.t and type a = A1.t and type b' := B1.t)
end
module AB = MakeAB(B.MakeB)
module A = AB.A
module B = AB.B
let a = A.Bar;;
let b = B.({ aaa = [a]; bo = None });;
let c = A.Foo b;;
let d = B.({ aaa = [a;c]; bo = Some b });;
Related
I have a type of two-way pointer list. What I have to do is to write a procedure, that given a list, should return a list which contain only elements on the odd indexes. I'm new into OCaml, and its pointer type data structures, this is what i`ve written so far, but it doesnt work.
Error: This expression has type 'a elem option
but an expression was expected of type 'b elem
type 'a elem =
{
v : 'a;
mutable next: 'a lista;
mutable prev: 'a lista;
}
and 'a lista = 'a elem option
exception NOT_FOUND
let x = ref None;;
let value e =
match e with
| Some x -> x.v
| None -> raise NOT_FOUND;;
let generuj n x =
x := Some {v = 0; next = None; prev = None};
for i = 1 to n do
match !x with
| None -> assert false
| Some y ->
let z = ref { v = i; next = None; prev = None } in
y.next <- Some !z;
!z.prev <- Some y;
x := Some !z
done
let second l x =
let i = ref 0 in
while !l <> None do
let z = ref !x in
if (!i mod 2 = 0) then
x := {v = value !l; next = None; prev = Some !z}
else ();
let y = !l.next in
l := {v = value y; next = y.next; prev = None};
i := !i + 1
done;;
Can anybody help me to understand why it doesnt work?
From the expression value !l you can conclude that l is of type 'a elem option ref. But in the expression !l.next you aren't handling l as an option type. You need to test whether !l is None or is Some ('a elem).
Note that you do compare l against None at the beginning of the function.
Also note that the next line has the same type error. You need to set l to Some ....
Consider for example let f x = f x in f 1. Is its signature defined?
If so, what is it?
One could argue, that OCaml doesn't know about the fact that it's not terminating and that its type is simply inferred as 'a. Is that correct?
let a b = let rec f x = f x in f 1;;
is for example val a : 'a -> 'b eventhough it is very clear, that when a is applied, there won't be a 'b
Then requirement for a sound type system when you have type(E) = T is that if E evaluates to some value v, then v is a value that belongs to type T. A type is meaningful when the expression gives a value, and exceptions and infinite loops do not.
The type checker however is total, and gives a type for all expression, even if it is just a free type variable.
Here the return type is left unbound, and is printed as 'a.
# let f x = if x then (failwith "A") else (failwith "B");;
val f : bool -> 'a = <fun>
Here the return type of the then branch is unified with the type of the else branch:
# let f x = if x then (failwith "A") else 5;;
val f : bool -> int = <fun>
#
One way to read function types like unit -> 'a is to remember that the
type variable 'a encompasses empty types.
For example, if I have a function f
let rec f:'a. _ -> 'a = fun () -> f ()
and an empty type
type empty = |
(* using 4.07 empty variants *)
(* or *)
type (_,_) eq = Refl: ('a,'a) eq
type empty = (float,int) eq
then I can restrict the type of f to unit -> empty:
let g: unit -> empty = f
Moreover, the more general type of f can be useful in presence of branches.
For instance, I could define a return that raises an exception in order
to exit early from a for-loop:
let search pred n =
let exception Return of int in
let return: 'a. int -> 'a = fun n -> raise (Return n) in
try
for i = 0 to n do
if pred i then return i
done;
None
with Return n -> Some n
Here, the polymorphic type of return makes it possible to use it in a context
where unit was expected.
Suppose a function g is defined as follows.
utop # let g ~y ~x = x + y ;;
val g : y:int -> x:int -> int = <fun>
utop # g ~x:1 ;;
- : y:int -> int = <fun>
utop # g ~y:2 ;;
- : x:int -> int = <fun>
utop # g ~x:1 ~y:2 ;;
- : int = 3
utop # g ~y:2 ~x:1 ;;
- : int = 3
Now there is another function foo
utop # let foobar (f: x:int -> y:int -> int) = f ~x:1 ~y:2 ;;
val foobar : (x:int -> y:int -> int) -> int = <fun>
Sadly when I try to provide g as the parameter of foobar, it complains:
utop # foobar g ;;
Error: This expression has type y:int -> x:int -> int
but an expression was expected of type x:int -> y:int -> int
This is quite surprising as I can successfully currify g but cannot pass it as the parameter. I googled and found this article which doesn't help much. I guess this is related to the underlying type system of OCaml (e.g. subtyping rules of labeled arrow types).
So is it possible to pass g as the parameter to foobar by any means in OCaml? If not, why is it not allowed? Any supporting articles/books/papers would be sufficient.
The key is that labels do not exist at runtime. A function of type X:int -> y:float -> int is really a function whose first argument is an int and whose second argument is a float.
Calling g ~y:123 means that we store the second argument 123 somewhere (in a closure) and we will use it automatically later when the original function g is finally called with all its arguments.
Now consider a higher-order function such as foobar:
let foobar (f : y:float -> x:int -> int) = f ~x:1 ~y:2.
(* which is the same as: *)
let foobar (f : y:float -> x:int -> int) = f 2. 1
The function f passed to foobar takes two arguments, and the float must be the first argument, at runtime.
Maybe it would be possible to support your wish, but it would add some overhead. In order for the following to work:
let g ~x ~y = x + truncate y;;
foobar g (* rejected *)
the compiler would have to create an extra closure. Instead you are required to do it yourself, as follows:
let g ~x ~y = x + truncate y;;
foobar (fun ~y ~x -> g ~x ~y)
In general, the OCaml compiler is very straightforward and won't perform this kind of hard-to-guess code insertion for you.
(I'm not a type theorist either)
Think instead of the types x:int -> y:float -> int and y:float -> x:int -> int. I claim these are not the same type because you can call them without labels if you like. When you do this, the first requires an int as its first parameter and a float as the second. The second type requires them in the reverse order.
# let f ~x ~y = x + int_of_float y;;
val f : x:int -> y:float -> int = <fun>
# f 3 2.5;;
- : int = 5
# f 2.5 3;;
Error: This expression has type float but an expression was
expected of type intÂ
Another complication is that functions can have some labelled and some unlabelled parameters.
As a result, the labeled parameters of a function are treated as a sequence (in a particular order) rather than a set (without an inherent order).
Possibly if you required all parameters to be labelled and removed the capability of calling without labels, you could make things work the way you expect.
(Disclaimer: I'm not a type theorist, though I wish I was.)
This pitfall of labels in OCaml is described in detail in the Labels and type inference subsection of the OCaml manual, giving an example similar to yours.
If I remember correctly, some type systems for labels lift that restriction, but at the cost of additional overall complexity that was judged "not worth it" for the OCaml language itself. Labels can be rearranged automatically at first-order application sites, but not when abstracting over labelled functions (or using such abstractions).
You can have your example accepted by manually eta-expanding the labelled function to make a reorderable application appear (a type-theorist would say this is a retyping eta-conversion):
# let f ~x ~y = x+y;;
val f : x:int -> y:int -> int = <fun>
# let yx f = f ~y:0 ~x:1;;
val yx : (y:int -> x:int -> 'a) -> 'a = <fun>
# yx f;;
Error: This expression has type x:int -> y:int -> int
but an expression was expected of type y:int -> x:int -> 'a
# yx (fun ~y ~x -> f ~y ~x);;
- : int = 1
I have extracted the following line from a function that's starts like so (textbook example incomplete):
let rec unify (exp1:exp) (exp2:exp) (k:(subst -> subst)) (sub:subst) =
match checkmap exp1 sub,checkmap exp2 sub with
| Var a,Var b when a = b -> k sub
| Var a,Var b -> k (safeInput<|||((safeInput<|||(sub,a,Var(b))),b,Var(a)))
Line:
Var a,Var b -> k (safeInput<|||((safeInput<|||(sub,a,Var(b))),b,Var(a)))
The safeInput reference 'safely' inputs a type into a Map structure... I am just wondering what the operators here are actually doing? Also, if there is a more intuitive way to structure the above line?
If you type
(<|||);;
into F# Interactive, you get its signature:
val it : (('a -> 'b -> 'c -> 'd) -> 'a * 'b * 'c -> 'd) = <fun:it#1>
Its definition is something like
let inline (<|||) f (a, b, c) = f a b c
so the last expression can be rewritten to
k (safeInput (safeInput sub a (Var b)) b (Var a))
To improve the function, you can also:
Create let bindings to hold immediate values
Reuse exp1 and exp2 instead creating the same values
e.g.
let rec unify (exp1 : exp) (exp2 : exp) (k : subst -> subst) (sub : subst) =
match checkmap exp1 sub,checkmap exp2 sub with
| Var a, Var b when a = b -> k sub
| Var a, Var b ->
let sub' = safeInput sub a exp2
k (safeInput sub' b exp1)
The <||| operator simply passes the arguments on the right (provided as a tuple) to the function on the left, so the line means the same as:
k (safeInput (safeInput sub a (Var b)) b (Var a))
Or, if you want to split the line into two to make it more readable:
let sub' = safeInput sub a (Var b)
k (safeInput sub' b (Var a))
I don't know the book that uses this, but I suppose the idea is to add mapping from variable 'a' to variable 'b' and another mapping back from variable 'b' to variable 'a'.
(A minimal non-compiling example can be found at https://gist.github.com/4044467, see more background below.)
I am trying to implement Bootstrapped Heaps introduced in Chapter 10 of Okasaki's Purely Functional Data Structure. The following is a simplified version of my non-compiling code.
We're to implement a heap with following signature:
module type ORDERED =
sig
type t
val compare : t -> t -> int
end
module type HEAP =
sig
module Elem : ORDERED
type heap
val empty : heap
val insert : Elem.t -> heap -> heap
val find_min : heap -> Elem.t
val delete_min : heap -> heap
end
We say a data structure is bootstrapped when its implementation depends on another implementation of the same kind of data structure. So we have a heap like this (the actual implementation is not important):
module SomeHeap (Element : ORDERED) : (HEAP with module Elem = Element) =
struct
module Elem = Element
type heap
let empty = failwith "skipped"
let insert = failwith "skipped"
let find_min = failwith "skipped"
let delete_min = failwith "skipped"
end
Then, the bootstrapped heap we're going to implement, which can depend on any heap implementation, is supposed to have the following signature:
module BootstrappedHeap
(MakeH : functor (Element : ORDERED) -> HEAP with module Elem = Element)
(Element : ORDERED) : (HEAP with module Elem = Element)
So we can use it like this:
module StringHeap = BootstrappedHeap(SomeHeap)(String)
The implementation of BootstrappedHeap, according to Okasaki, is like this:
module BootstrappedHeap
(MakeH : functor (Element : ORDERED) -> HEAP with module Elem = Element)
(Element : ORDERED) : (HEAP with module Elem = Element) =
struct
module Elem = Element
module rec BootstrappedElem :
sig
type t =
| E
| H of Elem.t * PrimH.heap
val compare : t -> t -> int
end =
struct
type t =
| E
| H of Elem.t * PrimH.heap
let compare t1 t2 = match t1, t2 with
| H (x, _), H (y, _) -> Elem.compare x y
| _ -> failwith "unreachable"
end
and PrimH : (HEAP with module Elem = BootstrappedElem) =
MakeH(BootstrappedElem)
type heap
let empty = failwith "not implemented"
let insert = failwith "not implemented"
let find_min = failwith "not implemented"
let delete_min = failwith "not implemented"
end
But this is not compiling! The error message is:
File "ordered.ml", line 52, characters 15-55:
Error: In this `with' constraint, the new definition of Elem
does not match its original definition in the constrained signature:
Modules do not match:
sig type t = BootstrappedElem.t end
is not included in
ORDERED
The field `compare' is required but not provided
The line 52 is the line
and PrimH : (HEAP with module Elem = BootstrappedElem) =
I think BootstrappedElem did implement ORDERED as it has both t and compare, but I failed to see why the compiler fails to find the compare function.
Change the signature of BootstrappedElem to
module rec BootstrappedElem : ORDERED
will make it compiling but this will hide the type constructor E and T in BootstrappedElem to make it impossible to implement the later parts.
The whole non-compiling code can be downloaded at https://raw.github.com/gist/4044281/0ce0336c40b277e59cece43dbadb9b94ce6efdaf/ordered.ml
I believe this might be a bug in the type-checker. I have reduced your code to the following example:
module type ORDERED =
sig
type t
val compare : t -> t -> int
end
module type CARRY = sig
module M : ORDERED
end
(* works *)
module HigherOrderFunctor
(Make : functor (X : ORDERED) -> (CARRY with module M = X))
= struct
module rec Base
: (ORDERED with type t = string)
= String
and Other
: (CARRY with module M = Base)
= Make(Base)
end
(* does not work *)
module HigherOrderFunctor
(Make : functor (X : ORDERED) -> (CARRY with module M = X))
= struct
module rec Base
: sig
(* 'compare' seems dropped from this signature *)
type t = string
val compare : t -> t -> int
end
= String
and Other
: (CARRY with module M = (Base : sig type t = string val compare : t -> t -> int end))
= Make(Base)
end
I don't understand why the first code works and the second (which seems equivalent) doesn't. I suggest you wait a bit to see if an expert comes with an explanation (Andreas?), then consider sending a bug report.
In this case, a solution is to first bind the signature that seems mishandled:
(* works again *)
module HigherOrderFunctor
(Make : functor (X : ORDERED) -> (CARRY with module M = X))
= struct
(* bind the problematic signature first *)
module type S = sig
type t = string
val compare : t -> t -> int
end
module rec Base : S = String
and Other : (CARRY with module M = Base) = Make(Base)
end
However, that is not possible in your setting, because the signature of BootstrappedElem is mutually recursive with BootstrappedHeap.
A workaround is to avoid the apparently-delicate with module ... construct and replace it with a simple type equality with type Elem.t = ...:
module BootstrappedHeap
(MakeH : functor (Element : ORDERED) -> HEAP with module Elem = Element)
(Element : ORDERED) : (HEAP with module Elem = Element) =
struct
module Elem = Element
module rec BootstrappedElem :
sig
type t =
| E
| H of Elem.t * PrimH.heap
val compare : t -> t -> int
end =
struct
type t =
| E
| H of Elem.t * PrimH.heap
let compare t1 t2 = match t1, t2 with
| H (x, _), H (y, _) -> Elem.compare x y
| _ -> failwith "unreachable"
end
and PrimH : (HEAP with type Elem.t = BootstrappedElem.t) =
MakeH(BootstrappedElem)
type heap
let empty = failwith "not implemented"
let insert = failwith "not implemented"
let find_min = failwith "not implemented"
let delete_min = failwith "not implemented"
end
You could also avoid the mutual recursion and define both BootstrappedElem and BootstrappedHeap in one recursive knot, by defining BootstrappedElem inside the recursive BootstrappedHeap.
module BootstrappedHeap
(MakeH : functor (Element : ORDERED) -> HEAP with module Elem = Element)
(Element : ORDERED) : (HEAP with module Elem = Element) =
struct
module rec BootstrappedHeap : sig
module Elem : sig
type t = E | H of Element.t * BootstrappedHeap.heap
val compare : t -> t -> int
end
include (HEAP with module Elem := Elem)
end = struct
module Elem = struct
type t = E | H of Element.t * BootstrappedHeap.heap
let compare t1 t2 = match t1, t2 with
| H (x, _), H (y, _) -> Element.compare x y
| _ -> failwith "unreachable"
end
include (MakeH(Elem) : HEAP with module Elem := Elem)
end
module Elem = Element
type heap
let empty = failwith "not implemented"
let insert = failwith "not implemented"
let find_min = failwith "not implemented"
let delete_min = failwith "not implemented"
end
This style corresponds naturally to your decision of embedding Elem in the HEAP signature and using with module ... for refinement. Another solution would have been to define HEAP as a functor returning a signature, used as HEAP(Elem).S, and I suppose a different recursive style could have been chosed. Not to say that this would have been better: I think the "abstract module" style is more convenient.