I am pretty sure I am not squinting hard enough to see where the mismatch is ... but I have been staring at my screen for a long time and thus asking this question.
My MLI file looks like
type ('k, 'v) t
val empty: ('k, 'v) t
val find: 'k -> ('k, 'v) t -> 'v option
val bindings: ('k, 'v) t -> ('k * 'v) list
val insert: 'k -> 'v -> ('k, 'v) t -> ('k, 'v) t
and I have an implementation for each of these in my ML file
type color = Red | Black
type ('k, 'v) t = Leaf | Node of (color * ('k, 'v) t * ('k * 'v) * ('k, 'v) t)
let empty = Leaf
let rec find k = function
| Leaf -> None
| Node (_, l, (x, y), r) ->
if k < x then find k l
else if k > x then find k r
else Some y
let rec bindings = function
| Leaf -> []
| Node (_, l, t, r) -> List.append (t :: bindings l) (bindings r)
let balance = function
| (Black, Node (Red, Node (Red, a, (xk, xv), b), (yk, yv), c), (zk, zv), d)
| (Black, a, (xk, xv) ,Node (Red, b, (yk, yv), Node (Red, c, (zk, zv), d)))
| (Black, Node (Red, a, (xk, xv), Node (Red, b, (yk, yv), c)), (zk, zv), d)
| (Black, a, (xk, xv), Node (Red, Node (Red, b, (yk, yv), c), (zk, zv), d))
-> Node (Red, Node (Black, a, (xk, xv), b), (yk, yv), Node (Black, c, (zk, zv), d))
| t -> Node t
let rec insert_aux k v = function
| Leaf -> Node (Red, Leaf, (k, v), Leaf)
| Node (c, l, (x, y), r) as n ->
if k < x then balance (c, insert_aux k v l, (x, y), r)
else if k > v then balance (c, l, (x, y), insert_aux k v r)
else n
let insert k v m =
match insert_aux k v m with
| Leaf -> failwith "Not possible"
| Node (_, l, t, r) -> Node (Black, l, t, r)
As you can see that the insert function has been implemented and I can see it has the right type being returned. but when I do dune build I get the following error from the ocaml compiler
File "redblacktreemap/redBlackTreeMap.ml", line 1:
Error: The implementation redblacktreemap/redBlackTreeMap.ml
does not match the interface redblacktreemap/.RedBlackTreeMap.objs/byte/redBlackTreeMap.cmi:
Values do not match:
val insert : 'a -> 'a -> ('a, 'a) t -> ('a, 'a) t
is not included in
val insert : 'k -> 'v -> ('k, 'v) t -> ('k, 'v) t
File "redblacktreemap/redBlackTreeMap.mli", line 19, characters 0-48:
Expected declaration
File "redblacktreemap/redBlackTreeMap.ml", line 32, characters 4-10:
Actual declaration
From the erroneous type a -> 'a -> ('a, 'a) t -> ('a, 'a) t you can see that your code is doing something that makes the compiler deduce that keys and values are the same type. This isn't what you want--the whole reason to have two type parameters (k, v) is so the types are independent.
Aha, you have this subexpression:
k > v
which means that k and v must be the same type.
Probably you meant k > x.
Related
type 'a tree =
| Leaf of 'a
| Node of 'a * 'a tree * 'a tree
let rec foldtree init op = function
| Leaf c -> op c init init
| Node (c, l, r) -> op c (foldtree init op l) (foldtree init op r)
let size' = foldtree 0 (fun _ l r -> 1 + l + r) (* this compiles fine *)
let size'' = foldtree 0 (fun _ l r -> 1 + l + r) (* this doesn't *)
In the above OCaml code, the definitions of size' and size'' are identical yet the latter causes a compilation error:
Error: The type of this expression, '_weak1 tree -> int,
contains type variables that cannot be generalized
They should both fail to compile, as both contain weak type variables. The compiler will only report one fatal error at a time, however.
Incidentally, you would usually fix this problem by eta-expansion:
let size tree = foldtree 0 (fun _ l r -> 1 + l + r) tree
I am writing a small interpreter in OCaml and am using GADTs to type my expressions:
type _ value =
| Bool : bool -> bool value
| Int : int -> int value
| Symbol : string -> string value
| Nil : unit value
| Pair : 'a value * 'b value -> ('a * 'b) value
and _ exp =
| Literal : 'a value -> 'a exp
| Var : name -> 'a exp
| If : bool exp * 'a exp * 'a exp -> 'a exp
and name = string
exception NotFound of string
type 'a env = (name * 'a) list
let bind (n, v, e) = (n, v)::e
let rec lookup = function
| (n, []) -> raise (NotFound n)
| (n, (n', v)::e') -> if n=n' then v else lookup (n, e')
let rec eval : type a. a exp -> a value env -> a value = fun e rho ->
match e with
| Literal v -> v
| Var n -> lookup (n, rho)
| If (b, l, r) ->
let Bool b' = eval b rho in
if b' then eval l rho else eval r rho
But I cannot get my code to compile. I get the following error:
File "gadt2.ml", line 33, characters 33-36:
Error: This expression has type a value env = (name * a value) list
but an expression was expected of type
bool value env = (name * bool value) list
Type a is not compatible with type bool
My understanding is that for some reason rho is being coerced into a bool value env, but I don't know why. I also tried the following:
let rec eval : 'a. 'a exp -> 'a value env -> 'a value = fun e rho ->
match e with
| Literal v -> v
| Var n -> lookup (n, rho)
| If (b, l, r) ->
let Bool b = eval b rho in
if b then eval l rho else eval r rho
But I am not sure how exactly that is different, and it also gives me an error -- albeit a different one:
File "gadt2.ml", line 38, characters 56-247:
Error: This definition has type bool exp -> bool value env -> bool value
which is less general than 'a. 'a exp -> 'a value env -> 'a value
Guidance on GADTs, differences between the two evals, and this particular problem are all appreciated. Cheers.
The type 'a env is intended to represent a list of name/value bindings, but the values in a list must all be the same type. Two different value types (such as bool value and int value) are not the same type. If eval b rho returns Bool b, rho must be a list of string * bool value. So eval l rho and eval r rho will return bool value. But your annotation says the function returns a value.
There are a few possible approaches to typed binding with GADTs. Here's a design that associates type info with both variables and environment entries.
Environment lookup involves attempting to construct a correspondence between the types of the variable and the environment entry (which is a bit slow, but does recover the type in a safe way). This is what allows the lookup to return an unwrapped value of arbitrary type.
type var = string
type _ ty =
| TyInt : int ty
| TyArrow : 'a ty * 'b ty -> ('a -> 'b) ty
type _ term =
| Int : int -> int term
| Var : 'a ty * var -> 'a term
| Lam : 'a ty * var * 'b term -> ('a -> 'b) term
| App : ('a -> 'b) term * 'a term -> 'b term
type ('a, 'b) eq = Refl : ('a, 'a) eq
let rec types_equal : type a b . a ty -> b ty -> (a, b) eq option =
fun a b ->
match a, b with
| TyInt, TyInt -> Some Refl
| TyArrow (x1, y1), TyArrow (x2, y2) ->
begin match types_equal x1 x2, types_equal y1 y2 with
| Some Refl, Some Refl -> Some Refl
| _, _ -> None
end
| _, _ -> None
type env = Nil | Cons : var * 'a ty * 'a * env -> env
let rec lookup : type a . a ty -> var -> env -> a =
fun ty var -> function
| Nil -> raise Not_found
| Cons (xname, xty, x, rest) ->
if var = xname then
match types_equal ty xty with
| Some Refl -> x
| None -> assert false
else
lookup ty var rest
let rec eval : type a . env -> a term -> a =
fun env -> function
| Int n -> n
| Var (ty, var) -> lookup ty var env
| App (f, x) -> (eval env f) (eval env x)
| Lam (arg_ty, arg_name, body) ->
fun arg_value ->
eval (Cons (arg_name, arg_ty, arg_value, env)) body
It is possible to have a typed interpreter that avoids the type reconstruction (and the string comparison!) by enforcing the correspondence between variable indices and environments at the type level, but that gets complicated.
Consider the following type:
data LTree a = Leaf a | Fork (LTree a) (LTree a)
build :: [(a,Int)] -> LTree a
build l = fst (buildaccum 0 l)e
I have a list and want to build a tree
buildaccum :: Int -> [(a,Int)] -> (LTree a, [(a,Int)])
buildaccum n l#((a,b):t) |n==b = (Leaf a,t)
|n<b = (Fork e d, l2)
where (e,l1) = buildaccum (n+1) l
(d,l2) = buildaccum (n+2) l1
In ghci, I get the following error:
Couldn't match expected type (LTree a, [(a, Int)])' with actual type LTree a'
Can you spot the error, please?
buildAccum must return a pair type (LTree a, [(a, Int)]), but in your first guarded statement you return a raw LTree a: Leaf a.
I have a parameterized type that recursively uses itself but with a type parameter specialized and when I implement a generic operator, the type of that operator is bound too tightly because of the case that handles the specialized sub-tree. The first code sample shows the problem, and the second shows a workaround that I'd rather not use because the real code has quite a few more cases so duplicating code this way is a maintenance hazard.
Here's a minimal test case that shows the problem:
module Op1 = struct
type 'a t = A | B (* 'a is unused but it and the _ below satisfy a sig *)
let map _ x = match x with
| A -> A
| B -> B
end
module type SIG = sig
type ('a, 'b) t =
| Leaf of 'a * 'b
(* Here a generic ('a, 'b) t contains a specialized ('a, 'a Op1.t) t. *)
| Inner of 'a * ('a, 'a Op1.t) t * ('a, 'b) t
val map : ('a -> 'b) -> ('a_t -> 'b_t) -> ('a, 'a_t) t -> ('b, 'b_t) t
end
module Impl : SIG = struct
type ('a, 'b) t =
| Leaf of 'a * 'b
| Inner of 'a * ('a, 'a Op1.t) t * ('a, 'b) t
(* Fails signature check:
Values do not match:
val map :
('a -> 'b) ->
('a Op1.t -> 'b Op1.t) -> ('a, 'a Op1.t) t -> ('b, 'b Op1.t) t
is not included in
val map :
('a -> 'b) -> ('a_t -> 'b_t) -> ('a, 'a_t) t -> ('b, 'b_t) t
*)
let rec map f g n = match n with
| Leaf (a, b) -> Leaf (f a, g b)
(* possibly because rec call is applied to specialized sub-tree *)
| Inner (a, x, y) -> Inner (f a, map f (Op1.map f) x, map f g y)
end
This modified version of Impl.map fixed the problem but introduces a maintenance hazard.
let rec map f g n = match n with
| Leaf (a, b) -> Leaf (f a, g b)
| Inner (a, x, y) -> Inner (f a, map_spec f x, map f g y)
and map_spec f n = match n with
| Leaf (a, b) -> Leaf (f a, Op1.map f b)
| Inner (a, x, y) -> Inner (f a, map_spec f x, map_spec f y)
Is there any way to get this to work without duplicating the body of let rec map?
Applying gasche's solution yields the following working code:
let rec map
: 'a 'b 'c 'd . ('a -> 'b) -> ('c -> 'd) -> ('a, 'c) t -> ('b, 'd) t
= fun f g n -> match n with
| Leaf (a, b) -> Leaf (f a, g b)
| Inner (a, x, y) -> Inner (f a, map f (Op1.map f) x, map f g y)
This style of recursion in datatype definitions is called "non-regular": the recursive type 'a t is reused at an instance foo t where foo is different from the single variable 'a used in the definition. Another well-known example is the type of full binary trees (with exactly 2^n leaves):
type 'a full_tree =
| Leaf of 'a
| Node of ('a * 'a) full_tree
Recursive functions that operate these datatypes typically suffer from the monomorphic recursion restriction of languages with type inference. When you do type inference you have to make a guess at what the type of a recursive function may be, before type-checking its body (as it may be use inside). ML languages refine this guess by unification/inference, but only monomorphic types may be inferred. If your function makes polymorphic uses of itself (it calls itself recursively on a different type that what it took as input), this cannot be inferred (it is undecidable in the general case).
let rec depth = function
| Leaf _ -> 1
| Node t -> 1 + depth t
^
Error: This expression has type ('a * 'a) full_tree
but an expression was expected of type 'a full_tree
Since 3.12, OCaml allows to use an explicit polymorphic annotation of
the form 'a 'b . foo, meaning forall 'a 'b. foo:
let rec depth : 'a . 'a full_tree -> int = function
| Leaf _ -> 1
| Node t -> 1 + depth t
You could do the same in your example. However, I wasn't able to
compile the type after using the annotation you have in your module
signature, as it appear to be wrong (the 'a_t are just weird). Here
is what I used to make it work:
let rec map : 'a 'b . ('a -> 'b) -> ('a Op1.t -> 'b Op1.t) ->
('a, 'a Op1.t) t -> ('b, 'b Op1.t) t
= fun f g n -> match n with
| Leaf (a, b) -> Leaf (f a, g b)
| Inner (a, x, y) -> Inner (f a, map f (Op1.map f) x, map f g y)
let rec add_tail l e = match l with
| [] -> [e]
| (h::t) -> h::(add_tail t e)
let rec fill_help l x n = match n = 0 with
true -> l
| false -> add_tail(l, x); fill_help(l, x, n-1)
let fill x n =
let l = [] in
fill_help(l, x, n)
and I'm getting the error in the interpreter
# #use "prac.ml";;
val prod : int list -> int = <fun>
val add_tail : 'a list -> 'a -> 'a list = <fun>
File "prac.ml", line 13, characters 21-27:
Error: This expression has type 'a * 'b
but an expression was expected of type 'c list
line 13 would be
| false -> add_tail(l, x); fill_help(l, x, n-1)
First of all you call fill_help with a tuple as an argument ((l, x, n-1)) even though it's not defined to take one. You should call fill_help as fill_help l x (n-1) instead. Same for add_tail.
Secondly you call a side-effect-free function (add_tail) and throw away its return value. This is almost always an error. It looks like you expect l to be different after the call to add_tail. It won't be. You probably want fill_help (add_tail l x) x (n-1).