A problem about inferring argument in Ocaml - ocaml

The following are some Ocaml codes using Ocaml and Yojson (a library support Json for Ocaml).
match feat_json with
| `Assoc [("goal",`List goal_feats_json);
("tactic", `String tac_str); ("arguments",`List args_feats_json)] ::tl ->
Then I show the definition of Yojson json type
type json = [ `Assoc of (string * json) list
| `Bool of bool
| `Float of float
| `Int of int
| `List of json list
| `Null
| `String of string ]
Both of goal_feats_json and args_feats_json have the type json.
The concrete type of goal_feats_json is [< Int of int ] list. The type of tac_str is string.
The concrete type of args_feats_json is [> Assoc of (string * [> Int of 'b | String of 'c ]) list ] list.
But when I compiled the file, the following error occurred.
Error: This expression has type [< `Int of 'a ] list but an expression was expected of type
[> `Assoc of (string * [> `Int of 'b | `String of 'c ]) list ] list*
It seems Ocaml treats both of goal_feats_json and args_feats_json as [< Int of int ] list. I have no idea why such an error happened. I would be much appreciated if anyone gives me some help.

There is no error in the code snippet that you showed, so it is impossible to know where lies the root issue. However, your type error can be solved with an explicit coercion. For instance,
let f (x:[< `Int of int]) = (x:>json)
Probably, you used goal_fets_json as an argument of a function that only works with values of type [<Int of _]` at some point, restraining its type.

Related

How do I Pattern-match GADT Types Get Alternative More Concrete Return Types?

I want to exploit GADT to implement the type ('a, 'b) liInstr_t in order to hold various types of instructions which are recursively decoded into basic operations (if need be) that then executed. (Eventually, I should construct more abstract types over them but in a mechanical, compositional and scripted fashion.) Unfortunately, I have difficulties associating the locally abstract types from pattern-matching function argument with the alternative concrete return types desired for the GADT.
I believe I'm missing something fundamental or making wrong assumptions though I have looked at the ocaml 4.10.0 manual on locally abstract types and gadts, the Real world Ocaml book, and the responses to similar questions such as here and here. This is because I seem to follow their explanations but cannot somehow apply them to my task.
From the above, I understand that polymorphic type variables annotate functions so that they can take on (be unified with) arbitrary types compatible with their constraints, and that locally abstract types let us have different types along alternative paths through a pattern-matching expression, say. Also, the local abstract types cannot be unified but can be refined to concrete types compatible with GADT result types. As such, GADTs can recurse over polymorphic types, and aggregate multiple result types into a single sum type.
I deliberately let the type ('a, 'b) liInstr_t have two type variables (so I can add more later), and its variants capture various constraint formats and scenarios I may have to use together.
type
liLabel_t = string (* Instruction name (label) *)
and
context_t = string (* TODO: execution context *)
and
'a context_list_t = 'a list
and
'a liChooser_t = 'a -> int (* get index of i-th list entry *)
and
('a, 'b) liInstr_t =
LiExec: 'a -> ('a, 'b) liInstr_t (* executable operation *)
| LiExecTRY: ('a, _) liInstr_t (* Ignore: Experiment on GADT *)
| LiLab: liLabel_t -> ('a, 'b) liInstr_t (* instruction label *)
| LiLabTRY: (liLabel_t, _) liInstr_t (* Ignore: Experiment on GADT *)
| LiSeq: 'a liChooser_t * 'b list -> ('a, 'b) liInstr_t (* sequence *)
| LiAlt: 'a liChooser_t * 'b list -> ('a, 'b) liInstr_t (* choice *)
| LiLoop: 'a liChooser_t * 'b list -> ('a, 'b) liInstr_t (* loop *)
| LiName: 'a liChooser_t * liLabel_t * 'b context_list_t ->
('a, 'b) liInstr_t (* change context *)
| Err_LiInstr: ('a, 'b) liInstr_t (* error handling *)
| Nil_LiInstr: ('a, 'b) liInstr_t (* no action *)
After experimenting, the sample function used is:
let ft1: type b c. (b, c) liInstr_t -> b = function
(* *) | LiExec n -> n
(* *) | LiExecTRY -> "4"
(* *) | LiLab s -> "LiLab"
(* *) | LiLabTRY -> "LiLabTRY"
(* *) | LiSeq (f, il) -> "LiSeq"
(* *) | LiAlt (f, il) -> "LiAlt"
(* *) | LiLoop (f, il) -> "LiLoop"
(* *) | LiName (f, il, ic) -> "LiName"
(* *) | Err_LiInstr -> "Err_LiInstr"
(* *) | Nil_LiInstr -> "Nil_LiInstr"
;;
and it gave the error:
Line 3, characters 22-25:
3 | (* *) | LiExecTRY -> "4"
^^^
Error: This expression has type string but an expression was expected of type
b
I still got errors when I changed the function annotation (and typing), or commented out some alternatives in the function pattern matching and the GADT type variants. Some of the errors (elided for brevity) were obtained as follows:
Using an extra locally-typed variable:
let ft1 : type b c d. (b, c) liInstr_t -> d = function ...
2 | (* *) | LiExec n -> n
^
Error: This expression has type b but an expression was expected of type d
Using only polymorphic type variables:
let ft1: 'b 'c. ('b, 'c) liInstr_t -> 'b = function ...
Error: This definition has type 'c. (liLabel_t, 'c) liInstr_t -> liLabel_t
which is less general than 'b 'c. ('b, 'c) liInstr_t -> 'b
My questions then are the following:
How can we capture and use the abstract types identified with alternative paths? A locally abstract type should bind (or be refined) to compatible concrete type(s) for values found in the resulting expression, or can be ignored, right? Ignoring recursion, this example:
let rec eval : type a. a term -> a = function
| Int n -> n (* a = int *)
| Add -> (fun x y -> x+y) (* a = int -> int -> int *)
| App(f,x) -> (eval f) (eval x)
(* eval called at types (b->a) and b for fresh b *)
on expression evaluation in the ocaml manual seems to suggest that is the case, at least for a 1-parameter GADT type. So, why aren't my types b and c not suitably bound (or refined) in the return type? And if they are binding (or being refined), which should bind to abstract type b and which to c, if at all? How can I find values for my return type so they can correctly associate with the abstract, value-less types reaching them. For, there is seems no way to obtain a result that has the type b in my first error above!
Why am I forced to have the same result type for the alternative paths to succeed (string type in my examples) whereas all possible result types of the GADT should be admissible. In this regard, the first variant (LiExec n -> n) seemed forced to have type string! Also, the abstract types and polymorphic variables along execution paths seem irrelevant to the result type!
I could not reproduce it but at one point, making the first variant LiExec n -> 4 seemed to require integer return values from all alternative pattern matches. If indeed this is the case, why should abstract types on alternative paths require values from the same non-GADT return type? (This behaviour is of non-polymorphic types, right?)
To work around incomprehensible issues on polymorphic types and locally abstract types, is there a simple way to mix them in a constraint? Various permutations to mix them always seem to result in a syntax error. e.g.:
let ft1: (type d) 'b 'c. ('b, 'c) liInstr_t -> d = function
^^^^
Error: Syntax error
Suppose we have the following GADT:
type _ simple_gadt =
| Con : 'a -> 'a simple_gadt
The type signature of Con can be understood as ('a : Type) -> 'a -> 'a simple_gadt (not real OCaml syntax); in other words, it takes a type as its first argument, and the rest of the type is dependent on this input type. The client provides the type; for example:
let value : int simple_gadt = Con 0
Implicitly, you can understand this definition as really meaning let value = Con(type int, 0), where the type is given as an argument (again, not real OCaml syntax).
When you write a function that takes a 'a simple_gadt as an argument, you don't know what 'a is. 'a is said to be an "existential type" provided by the caller of the function. Consider the following function:
let f (type a) (param : a simple_gadt) : a = match param with
| Con x -> x
The type of f is 'a . 'a simple_gadt -> 'a. A client can evaluate f (Con 0) and get back 0, of type int. A client can also evaluate f (Con true) and get back true, of type bool. The definition of the function has no control over what the actual type 'a is; only the caller does.
Suppose we attempt to define:
let g (type a) (param : a simple_gadt) : a = match param with
| Con _ -> ""
One would be able to evaluate g (Con 0) and get back "", a string, but based on the type of Con 0, the output of the function should be an int. This is clearly a type error, so g has an ill-typed definition, and the compiler rightfully rejects it. Likewise, your definition
let ft1: type b c. (b, c) liInstr_t -> b = function
(* ... *)
(* *) | LiExecTRY -> "4"
(* ... *)
is ill-typed because it assumes that b is string, while b could be any type that the caller provides. It looks like you have other similar type errors because you are attempting to pick more specific types for the existential types.
If the caller can choose any type, how can one use GADTs to "refine" the type variable to a more concrete type? The only way to do this is through the information that the caller provides.
Consider the following type definition:
type _ term =
| Abs : ('a -> 'b) -> ('a -> 'b) term
| App : ('a -> 'b) term * 'a term -> 'b term
| Bool : bool -> bool term
In a GADT, each constructor can make the type parameters more specific. Therefore, by pattern matching against each constructor, a function can refine the existential type parameter.
Consider this function on the GADT defined above:
let rec eval : 'a . 'a term -> 'a =
fun (type a) (term : a term) : a ->
match term with
| Abs f -> f
| App(f, x) -> (eval f) (eval x)
| Bool b -> b
In the Abs f case, Abs f is known to have type ('a -> 'b) term for some 'a and 'b by the definition of Abs. Similar reasoning applies for the App(f, x) and Bool b cases.
What's a universally quantified type from the caller's perspective (i.e. the caller can pick any type) must be an existentially quantified type from the callee's perspective (i.e. the callee must work with some fixed arbitrary type that the caller provides).
In brief, the type li_Instr_t as defined is not an interesting GADT and it can be rewritten to the strictly equivalent ADT
type ('a, 'b) liInstr_t =
| LiExec of 'a
| LiExecTRY
| LiLab of liLabel_t
| LiLabTRY
| LiSeq of 'a liChooser_t * 'b list
| LiAlt of 'a liChooser_t * 'b list
| LiLoop of 'a liChooser_t * 'b list
| LiName of 'a liChooser_t * liLabel_t * 'b context_list_t
| Err_LiInstr
| Nil_LiInstr
because the type declaration never introduces equations (or existential quantifications) between the result type and the constructor of the GADT.
If we look at a simple example for GADT:
type ('elt,'array) compact_array =
| String: (char, String.t) compact_array
| Float_array: (float, Float.Array.t) compact_array
| Standard: ('a, 'a array) compact_array
let init: type elt array.
(elt,array) compact_array -> int -> (int -> elt) -> array =
fun kind n f -> match kind with
| String -> String.init n f
| Float_array -> Float.Array.init n f
| Standard -> Array.init n f
The difference is that the constructor String constrains the type of compact_array to be (char,string) compact_array. Thus, when I observe String in the pattern matching above, I can introduce the equation
elt=char and array=string in the branch String and use those equation locally . Similarly, after observing the constructor Float_array in the pattern matching, I can work with the equation elt=float and array=Float.Array.t inside the corresponding branch.
Contrarily, with the definition of liInstr_t as it stands, observing a constructor of a value of type ('a,'b) liInstr_t brings no information on the type ('a,'b) liInstr_t. Consequently, the function ft1 of type type a b. (a,b) liInstr_t -> b is is promising to return a float array when called with ft1 (LiExecTRY:('a,float array) li_Instr_t). More generally, a function of type a b. (a,b) liInstr_t -> awhere no constructor impose a constraint onbis necessarily returning some value of typebthat was contained inside(a,b) liInstr_t` (or is not returning).
Using that knowledge, we can update your type liInstr_t to make the function ft1 works by adding the equations corresponding to the expected return type for ft1 to the definition of the type:
type liLabel_t = string
and context_t = string
and 'a context_list_t = 'a list
and 'a liChooser_t = 'a -> int
and ('a, 'b, 'ft1) liInstr_t =
| LiExec: 'a -> ('a, 'b,'a) liInstr_t (* ft1 returns the argument of LiExec *)
(* ft1 returns a string in all other cases *)
| LiExecTRY: ('a, 'b, string) liInstr_t
| LiLab: liLabel_t -> ('a, 'b, string) liInstr_t
| LiLabTRY: (liLabel_t, 'b, string) liInstr_t
| LiSeq: 'a liChooser_t * 'b list -> ('a,'b, string) liInstr_t
| LiAlt: 'a liChooser_t * 'b list -> ('a,'b, string) liInstr_t
| LiLoop: 'a liChooser_t * 'b list -> ('a,'b, string) liInstr_t
| LiName: 'a liChooser_t * liLabel_t * 'b context_list_t ->
('a,'b, string) liInstr_t
| Err_LiInstr: ('a, 'b, string) liInstr_t
| Nil_LiInstr: ('a, 'b, string) liInstr_t
and now that we have the right equation in place, we can define ft1 as:
let ft1: type a b c. (a, b, c) liInstr_t -> c = function
| LiExec n -> n
| LiExecTRY -> "4"
| LiLab s -> "LiLab"
| LiLabTRY -> "LiLabTRY"
| LiSeq (f, il) -> "LiSeq"
| LiAlt (f, il) -> "LiAlt"
| LiLoop (f, il) -> "LiLoop"
| LiName (f, il, ic) -> "LiName"
| Err_LiInstr -> "Err_LiInstr"
| Nil_LiInstr -> "Nil_LiInstr"
which typechecks without any error.

Polymorphic variants and let%bind type error

I'm trying to use the technique in Composable Error Handling in OCaml (Result type with polymorphic variants for errors) for some code I've written. The types of the functions I'm trying to use look like this:
val parse : parser -> token list -> (Nominal.term, [> `ParseError of string ]) Result.t
val lex : lexer -> string -> (token list, [> `LexError of string ]) Result.t
My attempt at composing them is this:
let lex_and_parse
: parser -> lexer -> string -> (Nominal.term, [> `ParseError of string | `LexError of string ]) Result.t
= fun parser lexer input ->
let open Result.Let_syntax in
let%bind tokens = lex lexer input in
parse parser tokens
Unfortunately the compiler (4.09.0) reports a type error:
File "src/Pratt.ml", line 147, characters 4-23:
147 | parse parser tokens
^^^^^^^^^^^^^^^^^^^
Error: This expression has type
(Nominal.term, [ `ParseError of string ]) result
but an expression was expected of type
(Nominal.term, [> `LexError of string ]) result
The first variant type does not allow tag(s) `LexError
Note that if I do the equivalent by hand, the code compiles:
let lex_and_parse
: parser -> lexer -> string -> (Nominal.term, [> `ParseError of string | `LexError of string ]) Result.t
= fun parser lexer input ->
match lex lexer input with
| Error (`LexError err) -> Error (`LexError err)
| Ok tokens ->
(match parse parser tokens with
| Ok result -> Ok result
| Error (`ParseError err) -> Error (`ParseError err))
Actually, that's not quite true. The equivalent is this, which also fails to compile (in the same way):
match lex lexer input with
| Error err -> Error err
| Ok tokens ->
match parse parser tokens with
| Ok result -> Ok result
| Error err -> Error err
File "src/Pratt.ml", line 155, characters 29-32:
155 | | Error err -> Error err
^^^
Error: This expression has type [ `ParseError of string ]
but an expression was expected of type
[> `LexError of string | `ParseError of string ]
The first variant type does not allow tag(s) `LexError
So my question is this. Note that the error message says "This expression has type (Nominal.term, [ `ParseError of string ]) result". This is what I don't understand -- I never specify that type anywhere, in fact, both places ParseError is mentioned, it's with a > constraint. So where does this type come from? IE where does [>ParseError of string ]become[ ParseError of string ]?
Also:
What's the difference between my attempt and Vladimir's original (which I assume compiles)?
Is there a way to weaken a polymorphic variant from [ x ] to [> x ]? (other than mapping all the tags by hand from the first type to the second)
Edit:
I uploaded all of my code for context.
Edit 2 (sorry):
I did some exploration and came up with this implementation:
let parse : parser -> token list -> (Nominal.term, [> `ParseError of string ]) Result.t
= fun parser toks ->
match expression parser toks with
(* | [], result -> result *)
(* | _, Error err -> Error err *)
| _, Ok _ -> Error (`ParseError "leftover tokens")
| _, _ -> Error (`ParseError "unimplemented")
If I remove either of the commented lines, the implementation of lex_and_parse starts to fail again. It's a bit disturbing to me that parse compiles and its type signature never changes, yet a caller can fail to typecheck. How is this possible? This kind of nonlocal effect seriously violates my expectation for how type checking / signatures (ought to) work. I'd really like to understand what's happening.
So first of all, your intuition is right, your code shall work, e.g., the following code is accepted by 4.09.0 without any type errors:
open Base
module type S = sig
type parser
type lexer
type token
type term
val parse : parser -> token list -> (term, [> `ParseError of string ]) Result.t
val lex : lexer -> string -> (token list, [> `LexError of string ]) Result.t
end
module Test (P : S) = struct
open P
let lex_and_parse :
parser -> lexer -> string -> (term, [> `ParseError of string | `LexError of string ]) Result.t
= fun parser lexer input ->
let open Result.Let_syntax in
let%bind tokens = lex lexer input in
parse parser tokens
end
module PL : S = struct
type parser
type lexer
type token
type term
let parse _parser _tokens = Error (`ParseError "not implemented")
let lex _ _ = Error (`LexError "not implemented")
end
So my question is this. Note that the error message says "This expression has type (Nominal.term, [ `ParseError of string ]) result". This is what I don't understand -- I never specify that type anywhere, in fact, both places ParseError is mentioned, it's with a > constraint. So where does this type come from? IE where does [>ParseError of string ]become[ ParseError of string ]?
You are right, this is the main culprit. For some reason, your parse function returns a value of type
(term, [`ParseError of string])
where the type of the error constituent is a ground type, i.e., it is not polymorphic and cannot be extended. It is hard to tell, why this has happened, but I bet that there should be some type annotation that you have put that stops the type checker from inferring the most general type for the parse function. In any case, the culprit is hiding somewhere and is not in the code that you have shown us.
Is there a way to weaken a polymorphic variant from [ x ] to [> x ]? (other than mapping all the tags by hand from the first type to the second)
Yes,
# let weaken x = (x : [`T] :> [> `T]);;
val weaken : [ `T ] -> [> `T ] = <fun>
What's the difference between my attempt and Vladimir's original (which I assume compiles)?
Your parse function in fact returns a non-extensible type. Note that to turn an non-extensible type to extensible, you have to use the full form coercion, e.g., if you will define lex_and_parse as
let lex_and_parse :
parser -> lexer -> string -> (term, [> `ParseError of string | `LexError of string ]) Result.t
= fun parser lexer input ->
let open Result.Let_syntax in
let parse = (parse
: _ -> _ -> (_, [ `ParseError of string]) Result.t
:> _ -> _ -> (_, [> `ParseError of string]) Result.t) in
let%bind tokens = lex lexer input in
parse parser tokens
it will compile. But again the main culprit is the type of your parse function.
Where the actual bug was hiding
After OP have uploaded the source code we were able to identify why and where the OCaml typechecker was denied from inferring the general and polymorphic type.
Here is the story, the parse function is implemented as
let parse : parser -> token list -> (Nominal.term, [> `ParseError of string ]) Result.t
= fun parser toks -> match expression parser toks with
| [], result -> result
| _, Ok _ -> Error (`ParseError "leftover tokens")
| _, Error err -> Error err
So its return type is a unification of the types of the folowing expressions:
result,
Error ('ParseError "leftover tokens")
Error err
in addition we have a type constraint
parser -> token list -> (Nominal.term, [> `ParseError of string ]) Result.t
And here is an important thing to understand, a type constrained is not a definition, so when you say let x : 'a = 42 you are not defining x to have a universal polymorphic type 'a. A type constraint (expr : typeexpr) forces the type of expr to be compatible with typexpr. In other words, type constraint can only constrain the type, but the type itself is always inferred by the type checker. If the inferred type is more general, e.g., 'a list than the constraint, e.g., int list, then it will be constrained to int list. But you can't move the other way around as it will defeat the type soundness, e.g., if the inferred type is int list and your constraint is 'a list, then it will still be 'a list (treat it like intersection of types). Again, the type inference will infer the most general type, and you can only make it less general.
So, finally, the return type of the parse subroutine is the result of unification of the three expressions above plus the user constraint. The type of result is the smallest type, since you have constrained the expression function here to return errors of the non-extensible ground type parse_error.
Now to mitigations.
The easiest solution is to remove type annotations at all and rely on the type checker, merlin, and well-defined interfaces (signatures) when you program. Indeed, the type annotation only confused you here. You wrote an extensible [> ...] type annotation and believed that the inferred type is extensible which wasn't true.
If you need to keep them or if you need to make the expression function a part of your interface, then you have two options, either make your parse_error extensible, and this means polymorphic or use type coercion to weaken the type of result and make it extensible, e.g.,
| [], result -> (result : parse_error :> [> parse_error])
If you will decide to make your parse_error type extensible, you can't just say
type parse_error = [> `ParseError of string]
because now parse_error denotes a whole family of types, so we need to represent this variability of type with a type variable, two syntaxes here are applicable,
type 'a parse_error = [>
| `ParseError of string
| `MoonPhaseError of int
] as 'a
or a more verbose, but to my taste more precise,
type 'a parse_error = 'a constraint 'a = [>
| `ParseError of string
| `MoonPhaseError of int
]
Both definitions are equivalent. The all mean that type 'a parser_error is a type variable 'a s.t. 'a includes the ParseError, the MoonPhaseError and infinitely more errors of unspecified genera.
The following functorized code:
module F(X: sig
type parser type lexer type token
module Nominal: sig type term end
val parse :
parser -> token list -> (Nominal.term, [> `ParseError of string ]) Result.t
val lex : lexer -> string -> (token list, [> `LexError of string ]) Result.t
end) = struct
open X
let (let*) x f = match x with
| Error _ as e -> e
| Ok x -> f x
let lex_and_parse parser lexer input =
let* tokens = lex lexer input in
parse parser tokens
end
compiles just fine with the expected type for lex_and_parse.
The issue is thus probably that your implementation of parse and lex have a closed error type.
Note that this issue could be fixed easily with a coercion since the closed error type is a subtype of the open one:
let fix parse =
(parse:
parser -> token list -> (Nominal.term, [`ParseError of string ]) Result.t
:> parser -> token list -> (Nominal.term, [>`ParseError of string ]) Result.t
)
but it is probably better to fix the implementation of the corresponding functions.
EDIT:
The initial error comes from this part of your code:
type parse_error = [ `ParseError of string ]
type parse_result = (Nominal.term, parse_error) Result.t
...
let rec expression
: parser -> ?rbp:int -> token list -> token list * parse_result
...
let parse :
parser -> token list -> (Nominal.term, [> `ParseError of string ]) Result.t
= fun parser toks -> match expression parser toks with
| [], result -> result
Here your are constraining the error in the parse_error type to be exactly `Parse_error. Thus, when you return result in parse, its type its (_,parse_error) result. And since this result type can be unified with your annotation, no error is raised.
Maybe a first fix is to detail the type to make the typechecker aware that you intended the error type to be open:
let parse : 'error.
parser -> token list ->
(Nominal.term, [> `ParseError of string ] as 'error) Result.t
= fun parser toks -> match expression parser toks with
| [], result -> result
Here, the explicit universal annotation on the return type will prevent the type to be closed behind your back (the error message might be confusing before 4.10 ).
Then, one possible fix is to add a coercion to reopen the error type in parse:
let parse : 'error.
parser -> token list ->
(Nominal.term, [> `ParseError of string ] as 'error) Result.t
= fun parser toks -> match expression parser toks with
| [], result -> (result:>(Nominal.term, [> parse_error]) result)
or you could make the error type of expression open too:
type parse_error = [ `ParseError of string ]
type 'a parse_result = (Nominal.term, [> parse_error] as 'a) Result.t
...
let rec expression
: parser -> ?rbp:int -> token list -> token list * 'a parse_result
= ...
Or an even easier fix: remove the type annotation, with
let rec expression parser ... =
without the type annotation, the compiler inferq the right type. Indeed, this is a quite generic situation: the compiler is guaranteed to infer the best possible type without user interference.

OCaml variance (+'a, -'a) and invariance

After writing this piece of code
module type TS = sig
type +'a t
end
module T : TS = struct
type 'a t = {info : 'a list}
end
I realised I needed info to be mutable.
I wrote, then :
module type TS = sig
type +'a t
end
module T : TS = struct
type 'a t = {mutable info : 'a list}
end
But, surprise,
Type declarations do not match:
type 'a t = { mutable info : 'a list; }
is not included in
type +'a t
Their variances do not agree.
Oh, I remember hearing about variance. It was something about covariance and contravariance. I'm a brave person, I'll find about my problem alone!
I found these two interesting articles (here and here) and I understood!
I can write
module type TS = sig
type (-'a, +'b) t
end
module T : TS = struct
type ('a, 'b) t = 'a -> 'b
end
But then I wondered. How come that mutable datatypes are invariant and not just covariant?
I mean, I understand that an 'A list can be considered as a subtype of an ('A | 'B) list because my list can't change. Same thing for a function, if I have a function of type 'A | 'B -> 'C it can be considered as a subtype of a function of type 'A -> 'C | 'D because if my function can handle 'A and 'B's it can handle only 'A's and if I only return 'C's I can for sure expect 'C or 'D's (but I'll only get 'C's).
But for an array? If I have an 'A array I can't consider it as a an ('A | 'B) array because if I modify an element in the array putting a 'B then my array type is wrong because it truly is an ('A | 'B) array and not an 'A array anymore. But what about a ('A | 'B) array as an 'A array. Yes, it would be strange because my array can contain 'B but strangely I thought it was the same as a function. Maybe, in the end, I didn't understand everything but I wanted to put my thoughts on it here because it took me long to understand it.
TL;DR :
persistent : +'a
functions : -'a
mutable : invariant ('a) ? Why can't I force it to be -'a ?
I think that the easiest explanation is that a mutable value has two intrinsic operations: getter and setter, that are expressed using field access and field set syntaxes:
type 'a t = {mutable data : 'a}
let x = {data = 42}
(* getter *)
x.data
(* setter *)
x.data <- 56
Getter has a type 'a t -> 'a, where 'a type variable occurs on the right-hand side (so it imposes a covariance constraint), and the setter has type 'a t -> 'a -> unit where the type variable occurs to the left of the arrow, that imposes a contravariant constraint. So, we have a type that is both covariant and contravariant, that means that type variable 'a is invariant.
Your type t basically allows two operations: getting and setting. Informally, getting has type 'a t -> 'a list and setting has type 'a t -> 'a list -> unit. Combined, 'a occurs both in a positive and in a negative position.
[EDIT: The following is a (hopefully) clearer version of what I wrote in the first place. I consider it superior, so I deleted the previous version.]
I will try to make it more explicit. Suppose sub is a proper subtype of super and witness is some value of type super which is not a value of type sub. Now let f : sub -> unit be some function which fails on the value witness. Type safety is there to ensure that witness is never passed to f. I will show by example that type safety fails if one is allowed to either treat sub t as a subtype of super t, or the other way around.
let v_super = ({ info = [witness]; } : super t) in
let v_sub = ( v_super : sub t ) in (* Suppose this was allowed. *)
List.map f v_sub.info (* Equivalent to f witness. Woops. *)
So treating super t as a subtype of sub t cannot be allowed. This shows covariance, which you already knew. Now for contravariance.
let v_sub = ({ info = []; } : sub t) in
let v_super = ( v_sub : super t ) in (* Suppose this was allowed. *)
v_super.info <- [witness];
(* As v_sub and v_super are the same thing,
we have v_sub.info=[witness] once more. *)
List.map f v_sub.info (* Woops again. *)
So, treating sub t as a subtype of super t cannot be allowed either, showing contravariance. Together, 'a t is invariant.

How to get type information in interactive Ocaml?

I am using Ocaml of version 4. When I define interactively some type, the interpreter prints out string representation of the type immediately after that:
# type foo = Yes | No;; <-- This is what I entered
type foo = Yes | No <-- This is what interpreter bounced
But after I type more definitions, sometimes I want to see the text representation of the type again.
In Haskell, I could type ":t foo".
How can I do this in Ocaml?
In utop you can use the #typeof directive:
#typeof "list";;
type 'a list = [] | :: of 'a * 'a list
You can put values and types inside double quotes:
let t = [`Hello, `World];;
#typeof "t";;
val t : ([> `Hello ] * [> `World ]) list
P.S. And even better solution would be to use merlin.
As far as I know, there is actually no way in Ocaml to retrieve type information under a string form
You'll have to build a pattern matching for each of your type
type foo = Yes | No;;
let getType = function
|Yes -> "Yes"
|No -> "No"
;;
let a = Yes;;
print_string (getType a);;

Function of type ('a -> 'b) list -> 'a -> 'b list in OCaml

Write any Ocaml function whose type is ('a -> 'b) list -> 'a -> 'b list
('a -> 'b) list is the part that confuses me the most. I'm new to OCaml and having a hard time understanding how to write a function to get a specific datatype type.
# let int x = x+1;;
# let fcn = [int; int];;
So I'm passing a function a function and a variable. I'm going to take that variable an add it to each element of the list and return the list?
('a -> 'b) means a function which goes from type 'a to type 'b. Basically you need to make a function which takes a list of functions that take 'a and return 'b, plus a specific 'a value, and which returns a list of 'b values (probably by applying each function of the list of functions to the specific 'a value).
As this is homework, I will not provide you with a complete solution. But, as a hint, I would suggest that you take a look at this implementation of the familiar map function:
let rec map f = function
| [] -> []
| x :: xs -> f x :: map f xs
It has type ('a -> 'b) -> 'a list -> 'b list which means that it takes as its first argument a function that takes values of some type 'a to values of some type 'b, as its second argument a list of elements of type 'a, and that it produces a list of elements of type 'b. It proceeds by pattern matching on the argument list and, recursively applying the function (f) to every element x of the list.
Now have a look at the type of the function that you have to write? What does it tell you about the required behaviour of that function? Keeping the implementation of the map function in mind, how would you write your function?
('a -> 'b) list -> 'a -> 'b list
This means that your function has two parameters
A list of ('a -> 'b) which represents a function taking an element of type 'a as a parameter and returning an element of type 'b. As you can see, these types are abstract, so they could be of any types for instance (int -> int) or (int -> float) etc...
An elements of types 'a. Notice that this type must be the same as the parameter of your function.
So you'll build the resulting list with the element you give as a parameter.
Here is a little example:
let action l a =
let rec todo l res =
match l with
| [] -> res
| h :: t -> todo t res#[h a] in
todo l []
so here, any function of type int -> int will be accepted. The same thing goes for any other type as long as you don't mix them with other types.
let rec func f a = match f with (* ( 'a->'b ) list -> 'a -> 'b list *)
|[]->[]
|x::lr -> x a :: func lr a;;
that may help ! it works fine
1 - So as we know , ocaml create the type of our function line by line
2 - in this function we have two arguments f and a
3 - ( 'a->'b ) list : for f
4 - 'a : for a ! how ocaml did that ? listen !
5 - when we matched f with [ ] 'blank list' ocaml release that is a list (****)list but doesn't know what contains yet in the last line of the code he will do ok ? nice !
- here we are in the last line of the code and we have only f of type list -
6 - x :: lr means we sort the first element of the element that is matched before : f and we add a here ocaml gives a type for a and for the list elements which is matched : f as first elements ocaml gives them types from 'a to 'z so here we have ('a->'b) list for f and 'a for a
-here we have f of type : ('a->'b) list , and a of type : 'a
7 - the result of this function 'b list so it's up to you to answer in comment ! :D thank you