I have the following generic variant type:
type 'a t = A | B | C | D | E | Value of 'a
and some function that converts int t to string t
let int_to_sting = function
| Value x -> Value (string_of_int x)
| some -> some
This function is uncompilable because of
| some -> some
Error: This expression has type int t but an expression was expected
of type string t
Type int is not compatible
Even it has type annotation.
let int_to_sting : int t -> string t = function
| Value x -> Value (string_of_int x)
| some -> some
I can rewrite it with
let int_to_sting = function
| Value x -> Value (string_of_int x)
| A -> A
| B -> B
| C -> C
| D -> D
| E -> E
But the long list of constructors looks redundancy.
Is it possible to convert some in my first implementation to avoid this noisy code?
You can make it slightly less redundant by both enumerating and binding them to a name:
let int_to_sting = function
| Value x -> Value (string_of_int x)
| (A | B | C | D | E) as some -> some
Another option that is OBVIOUSLY NOT SAFE and that you DEFINITELY SHOULDN'T USE is to circumvent the type system using Obj.magic:
let int_to_sting = function
| Value x -> Value (string_of_int x)
| some -> (Obj.magic (some: int t): string t)
This happens to work because the representation of these values are the same regardless of the type argument. But if you were to add another constructor that is not... then you crash and burn.
Related
I am new to OCaml. And I am writing a simple assembler compiler. I have the following types which I use in my AST.
type asmreg8
type asmreg16
type asmreg32
type asmreg64
type asmreg128
type _ reg =
| Reg8 : string -> asmreg8 reg
| Reg16 : string -> asmreg16 reg
| Reg32 : string -> asmreg32 reg
| Reg64 : string -> asmreg64 reg
| Reg128 : string -> asmreg128 reg
type asmlabel
type _ const = ASMConst of string const
type _ var = ASMVar of string var
type _ label = ASMLabel of asmlabel label
type double_arg =
| RegToReg : 'a reg * 'a reg -> double_arg
| RegToConst : 'a reg * 'b const -> double_arg
type mnemonic = Mov | Add | Inc | Ret
type single_arg =
| Var : _ var -> single_arg
| Reg : _ reg -> single_arg
| Label : _ label -> single_arg
type command =
| Args2 of mnemonic * double_arg
| Args1 of mnemonic * single_arg
| Args0 of mnemonic
type code_section = Command of command | Id of asmlabel label
type data_type = DB | DW | DD | DQ | DT
type var = string * data_type * string list
type dir = Code of code_section list | Data of var list
I think types are good because they forbid operations on different (by bits) registers. But now I have a problem. I do not know how to write a function like the following
let string_to_reg = function
| "something" -> Reg8 "something"
| "Reg16" -> Reg16 "16"
| _ -> Reg32 "123"
I just do not know how to get a function that takes a string (or another type that does not explicitly contain 'a) and returns values of type 'a reg where 'a can be asmreg8, asmreg16 ets.
I have read several articles about GADT and phantom types, but have not found an example that suits me. I'm starting to think I'm missing something about types and that things should be a lot simpler.
I tried this code `
let string_to_reg : type a. string -> a reg = function
| "something" -> Reg8 "something"
| "Reg16" -> Reg16 "16"
| _ -> Reg32 "123"
but I get
This expression has type asmreg8 reg but an expression was expected of type
a reg
Type asmreg8 is not compatible with type a
I thought I can just show to compiler that the function returns a polymorphic type.
I tried this
let string_to_reg : string -> 'a reg = function
| "something" -> Reg8 "something"
| "Reg16" -> Reg16 "16"
| _ -> Reg32 "123"
but I get a string -> asmreg8 reg function and it can not return value of asmreg16 reg type.
I tried pack my _ ret types by another type
type asmreg =
| ASM8 : asmreg8 reg -> asmreg
| ASM16 : asmreg16 reg -> asmreg
| ASM32 : asmreg32 reg -> asmreg
| ASM64 : asmreg64 reg -> asmreg
| ASM128 : asmreg128 reg -> asmreg
let reg_to_asmreg : type a. asmreg -> a reg = function
| ASM8 x -> Reg8 x
| ASM16 x -> Reg16 x
| _ -> Reg32 "123"
but I have a same problem. I can not write a function that returns values of different reg types.
It is not possible to write the function string_to_reg directly
let string_to_reg s x = match x with
| "something" -> Reg8 "something"
| "Reg16" -> Reg16 "16"
| _ -> Reg32 "123"
because the type of the function would not be 'a. string -> 'a reg. Indeed this type means that the function returns a register of all possible type simultaneously which is not what you meant.
The correct type of the result of the function would be something like
(x:string) -> reg_type(x) in a dependently typed language. In other words, you want the type of the result to depend on the value of its argument. This is not possible in OCaml (in the core language).
This is common issue when interfacing a strongly typed GADT DSLs with the exterior world. The solution is to use another layer of GADTs to convey the information that the type of the parsed register cannot be known in advance:
type dyn_reg = Dyn: 'any reg -> dyn_reg [##unboxed]
let string_to_dyn_reg s = function
| "something" -> Dyn (Reg8 "something")
| "Reg16" -> Dyn(Reg16 "16")
| _ -> Dyn(Reg32 "123")
Here, if I have a value Dyn x, I know that there is some type 'e such that the type of x is x:'e reg, but I don't know anything more about this type 'e (this kind of type variable 'e is said to be existentially quantified type). Thus I can only apply function on x that work for any 'e reg.
Since reg is a GADTs, the possible values for 'e reg are well-known, so there are still many useful function of type 'e. 'e reg -> ... and it should still possible to use the parsed register.
An important point to notice however is that this dyn_reg type has mostly erased all fine-grained type information that was available on the GADTs definition, and whenever we are using dyn_reg, we are in fact using an encoding of the normal variants. Thus, if you end up using only dyn_reg, it is a sign that GADTs were not really useful in this case.
EDIT:
A good example of the consequence of erasing the types is to try to write a move function.
Just writing
let mov (Dyn a) (Dyn b) =
Args2(Mov, RegToReg(a,b)
fails because the type of a and b might not be compatible.
However, once we check that the types are compatible, the function
compiles as expected
exception Type_error
let mov (Dyn a) (Dyn b) =
let matching x y = Args2(Mov,RegToReg(x,y)) in
match a, b with
| Reg8 _, Reg8 _ -> matching a b
| Reg16 _, Reg16 _ -> matching a b
| Reg32 _, Reg32 _ -> matching a b
| Reg64 _, Reg64 _ -> matching a b
| Reg128 _, Reg128 _ -> matching a b
| _ -> raise Type_error
I was working on chapter 1 of Modern Compiler Implementation in ML by Andrew Appel and I decided to implement it in OCaml instead of SML. I'm new to OCaml and I came across a very frustrating problem. OCaml seems to think that the below function has the signature int * (int * 'a) -> 'a option.
let rec lookupTable = function
| name, (i, v) :: _ when name = i -> Some v
| name, (_, _) :: rest -> lookupTable (name, rest)
| _, [] -> None
But as far as I can tell, there should be nothing that suggests that the first element in the tuple is an int. This is a problem because when the lookupTable function down the line, the compiler complains that I am not passing it an integer. Perhaps I am missing something incredibly obvious, but it has been pretty mind-boggling. Here is the rest of the program
open Base
type id = string
type binop = Plus | Minus | Times | Div
type stm =
| CompoundStm of stm * stm
| AssignStm of id * exp
| PrintStm of exp list
and exp =
| IdExp of id
| NumExp of int
| OpExp of exp * binop * exp
| EseqExp of stm * exp
(* Returns the maximum number of arguments of any print
statement within any subexpression of a given statement *)
let rec maxargs s =
match s with
| CompoundStm (stm1, stm2) -> Int.max (maxargs stm1) (maxargs stm2)
| AssignStm (_, exp) -> maxargs_exp exp
(* Might be more nested expressions *)
| PrintStm exps -> Int.max (List.length exps) (maxargs_explist exps)
and maxargs_exp e = match e with EseqExp (stm, _) -> maxargs stm | _ -> 0
and maxargs_explist exps =
match exps with
| exp :: rest -> Int.max (maxargs_exp exp) (maxargs_explist rest)
| [] -> 0
type table = (id * int) list
let updateTable name value t : table = (name, value) :: t
let rec lookupTable = function
| name, (i, v) :: _ when name = i -> Some v
| name, (_, _) :: rest -> lookupTable (name, rest)
| _, [] -> None
exception UndefinedVariable of string
let rec interp s =
let t = [] in
interpStm s t
and interpStm s t =
match s with
| CompoundStm (stm1, stm2) -> interpStm stm2 (interpStm stm1 t)
| AssignStm (id, exp) ->
let v, t' = interpExp exp t in
updateTable id v t'
(* Might be more nested expressions *)
| PrintStm exps ->
let interpretAndPrint t e =
let v, t' = interpExp e t in
Stdio.print_endline (Int.to_string v);
t'
in
List.fold_left exps ~init:t ~f:interpretAndPrint
and interpExp e t =
match e with
| IdExp i -> (
match lookupTable (i, t) with
| Some v -> (v, t)
| None -> raise (UndefinedVariable i))
| NumExp i -> (i, t)
| OpExp (exp1, binop, exp2) ->
let exp1_val, t' = interpExp exp1 t in
let exp2_val, _ = interpExp exp2 t' in
let res =
match binop with
| Plus -> exp1_val + exp2_val
| Minus -> exp1_val - exp2_val
| Times -> exp1_val * exp2_val
| Div -> exp1_val / exp2_val
in
(res, t')
| EseqExp (s, e) -> interpExp e (interpStm s t)
Base defines = as int -> int -> bool, so when you have the expression name = i the compiler will infer them as ints.
You can access the polymorphic functions and operators through the Poly module, or use a type-specific operator by locally opening the relevant module, e.g. String.(name = i).
The reason Base does not expose polymorphic operators by default is briefly explained in the documentation's introduction:
The comparison operators exposed by the OCaml standard library are polymorphic:
What they implement is structural comparison of the runtime representation of values. Since these are often error-prone, i.e., they don't correspond to what the user expects, they are not exposed directly by Base.
There's also a performance-argument to be made, because the polymorphic/structural operators need to also inspect what kind of value it is at runtime in order to compare them correctly.
In order to map from a constructed type tainted_value to other types, and from other basic types to the constructed type tainted_value, there are two functions constructed.
First, the type tainted_value is defined as:
type object_ = int
and location = Obj of object_ | Null
and closure = var * cmd * stack
and value = Fld of string | Int of int | Loc of location | Clo of closure
and tainted_value = Val of value | Error
If I just let my first function mapping from tainted_value to string look like:
let tva_to_string tva1 = match tva1 with
| Val (Fld e) -> e
| _ -> None
It reports error as:
This expression has type 'a option but an expression was expected of type string
However, it will not return error if I change None into failwith "Empty":
let tva_to_string tva1 = match tva1 with
| Val (Fld e) -> e
| _ -> failwith "Empty"
Why?
None is a constructor for the option type. If one clause in a match returns None then the others must return some other value of type option. They may also raise an exception, which is what the failwith function does.
The other constructor for option is Some, so you may be looking for:
let tva_to_string tva1 = match tva1 with
| Val (Fld e) -> Some e
| _ -> None
This will alleviate your type-checking issues. Of course, it still doesn't return a string so your naming of the function either needs some work, or you need to return strings.
I write an interpreter with Ocaml but when i try :
sem(Let("Somma",Fun("x",Sum(Den "x",Eint(5))),Let("pipa",Pipe(Seq(Den "Somma",Nil)),Apply(Den "pipa",Eint(42)))),(emptyenv Unbound));;
the resault is an error : "Exception: Match_failure ("",1,41)
I think that error is in applyPipe but I don't understand where and why there is
Where did i wrong?
this is my code :
type exp =
.
.
.
| Fun of ide * exp
| Apply of exp * exp
| Letrec of ide * ide * exp * exp
| Etup of tuple (*Tupla come espressione*)
| Pipe of tuple (*Concatenazione di funzioni*)
| ManyTimes of int * exp (*Esecuzione iterata di una funzione*)
and tuple =
| Nil (*Tupla vuota*)
| Seq of exp * tuple (*Tupla di espressioni*)
;;
type eval=
| Int of int
| Bool of bool
| Unbound
| RecFunVal of ide * ide * exp * eval env
| Funval of efun
| ValTup of etuple
and efun = ide * exp * eval env
and etuple =
| Nil
| Seq of eval * etuple
;;
let rec sem ((ex: exp), (r: eval env)) = match ex with
.
.
.
| Let(i, e1, e2) -> sem(e2, bind (r, i, sem(e1, r)))
| Fun(i,a) -> Funval(i,a,r)
| Letrec(f, i, fBody, letBody) ->
let benv = bind(r, f, (RecFunVal(f, i, fBody, r)))
in sem(letBody, benv)
| Etup(tup) -> (match tup with
| Seq(ex1, tupla) ->
let evex1 = sem(ex1, r) in
let ValTup(etupl) = sem(Etup(tupla), r) in
ValTup(Seq(evex1, etupl))
| Nil -> ValTup(Nil))
| Apply(Den f, arg1) ->
(let fclosure= sem(Den f, r) in
match fclosure with
| Funval(arg, fbody, fDecEnv) ->
sem(fbody, bind(fDecEnv, arg, sem(arg1, r)))
| RecFunVal(f, arg, fbody, fDecEnv) ->
let aVal= sem(arg1, r) in
let rEnv= bind(fDecEnv, f, fclosure) in
let aEnv= bind(rEnv, arg, aVal) in
sem(fbody, aEnv)
| _ -> failwith("non functional value"))
| Apply(Pipe tup, arg) -> applyPipe tup arg r
| Apply(_,_) -> failwith("not function")
| _ -> failwith("non implementato")
and applyPipe tup argo r = (match tup with
| Seq(Den f, tupla) ->
let appf = Apply(Den f,argo) in
applyPipe tupla appf r
| Nil -> sem(argo,r)
| _ -> failwith("Not a valid Pipe"))
;;
The complete code is there : http://pastebin.com/VgpanX51
Please help me thaks
When you compile (or evaluate in a toplevel) an OCaml program, a typechecker will emit warnings about all pattern matches that are irrefutable, i.e., such patterns that may raise a Match_failure exception.
What you should do, is to go through all warnings and fix them.
There are quite a few irrefutable matches in your code, e.g., the sem function final match Apply(_,_) -> failwith("not function") will only catch Apply terms, but will not catch all others, adding something like _ -> failwith "unimplemented" will fix it.
QA
the error is in the try-code or in my interpreter?
It is in the interpreter, you didn't include all possible cases in your pattern-matching code.
.I do extend the typechecker
You don't need to. The typechecker verifies whether you anticipated all possible cases, for example, let's take the simple example:
type abc = A | B | C
let string_of_abc abc = match abc with
| A -> "A"
| B -> "B"
When you will try to compile (or interpret) the above code the typechecker will tell you:
Warning 8: this pattern-matching is not exhaustive.
Here is an example of a value that is not matched:
C
type abc = A | B | C
So, it gives you a hint, that you forgot to match with the C constructor, so the expression string_of_abc C will terminate with a Match_failure exception.
You can follow the hints and add the cases one-by-one. Given your example, the pattern matching in the sema function is incomplete, and the type checker hits you with the following:
Warning 8: this pattern-matching is not exhaustive.
Here is an example of a value that is not matched:
(Pipe _|ManyTimes (_, _))
And indeed, you missed the case with Pipe, so when the interpreter sees
Pipe(...)
It can't find a match, as according to your code you're expecting the Pipe constructor only as a first argument to Apply, when in your example, you're actually passing it as a second argument to Let.
suppose I have the following code:
type s = A of a | B of b
let foo (a:?) =
let bar (input:s) = match input with
| A a -> foo input
| B b -> ...
My question is what should I fill in the question mark in the signature of foo so I won't need a (redundant) match statement in it? Or is there a better pattern to do this?
If you want to avoid rematch, I see 3 solutions:
have the function foo simply take the "payload" of the value constructor A, and reconstruct a value of type s as its output (or any other type matching the output type of bar).
# type a;;
type a
# type b;;
type b
# module Ex1 = struct
type s = A of a | B of b
let foo (a:a) = A a
let bar (input:s) = match input with
| A a -> foo a
| B b -> (* ... *) input
end;;
module Ex1 :
sig
type s = A of a | B of b
val foo : a -> s
val bar : s -> s
end
use polymorphic variants:
# module Ex2 = struct
type s = [ `A of a | `B of b ]
let foo (`A a) = `A a
let bar (input:s) = match input with
| `A _ as a -> foo a
| `B b -> (* ... *) input
end;;
module Ex2 :
sig
type s = [ `A of a | `B of b ]
val foo : [< `A of 'a ] -> [> `A of 'a ]
val bar : s -> s
end
use GADTs:
# module Ex3 = struct
type _ s =
| A : a -> a s
| B : b -> b s
let foo (a: a s) : a s =
match a with
| A a -> A a
let bar: type x. x s -> x s = fun input ->
match input with
| A _ as a -> foo a
| B b -> (* ... *) input
end;;
module Ex3 :
sig
type _ s = A : a -> a s | B : b -> b s
val foo : a s -> a s
val bar : 'x s -> 'x s
end
Starting with your example, the solution would be simple:
type s = A of a | B of b
let foo (a:a) =
let bar (input:s) = match input with
| A a -> foo a
| B b -> ...
But constraint here is not needed. Looks like that you're misunderstanding the idea of type constraints. In general, in OCaml type constraints cannot affect the program. Programs with and without type constraints have the same behavior. So, here you don't need to put any constraints at all. You must think of type annotations only as a helper tool for programmer.
Update
I'm still not sure, that I understand what actually you want, but if you want to split your variants into subsets, and keep this split refutable, then, indeed, you can use polymorphic variants, as Pascal suggested.
Let me first rephrase the questions. Suppose I have type:
type t = A | B | C | D | E
and I have a pattern match
let f = function
| A | B | C as x -> handle_abc x
| D | E as x -> handle_de x
How can I prove to a compiler, that handle_abc takes only a subset of all possible constructors, namely A | B | C ?
The answer is, with regular variants it is impossible. But it is possible with polymorphic variants:
type t = [`A | `B | `C | `D | `E]
let f = function
| `A | `B | `C as x -> handle_abc x
| `D | `E as -> handle_de x
So, handle_abc now needs only to pattern match on three variants, and don't need to have any redundant matches. Moreover, you can give names to a groups of constructors, and pattern match on this names:
type abc = [`A | `B | `C ]
type de = [`D | `E ]
type t = [ abc | de ]
let f = function
| #abc as x -> handle_abc x
| #de as -> handle_de x
As a real world example, you can take a look at BAP project where polymorphic variants are used to represent instruction code. Here we split all codes into different subgroups, like all move instructions, all branch instructions and so on. And later we can pattern match on the groups directly.
One solution, that incurs a runtime cost, would be to have the variants wrap tuples instead of individual values. Then it's easier to capture the whole tuple and send it to a specialized function:
type s =
(* Note the extra parentheses! *)
| Foo of (int * string)
| Bar of (char * int * string)
let foo (i, s) = "foo"
let bar (c, i, s) = "bar"
let main input =
match input with
| Foo f -> foo f (* `f` is bound to a tuple of type `int * string` *)
| Bar b -> bar b (* `b` is bound to a tuple of type `char * int * string` *)
You would have to fill in the type in the question mark for the signature of Foo, and then use a match statement in it. The place where the question mark is denotes a type. In a way it is assisting the compiler by telling it what exact type you want, and it will strictly ensure that operations you carry out on a or input is of a matching type.
The match statement is not that redundant and does not hurt performance much as it is very efficient in OCaml. However we have another approach as below.
Alternatively if you only have one parameter, you could save some typing by doing function in place of match. For example:
let foo (c:s) = match c with ....
we can do
let foo = function
| A -> ...
| B -> ...
Note that the function word will only work if you have one parameter passed in (you could definitely wrap up all your parameters into a list and pass it in if you like)
Here's an additional example to get my point across:
type number = |Int of int
|Float of float
let to_int: (number -> int option) = function
| Int n -> Some n
| _ -> None
(*this is the same as *) (*also note that int option denotes return type*)
let to_int (input:number) : int option =
match input with
| Int n -> Some n
| _ -> None
(*notice how the first one does not have a input as a parameter name*)
let n1:number = Int 1;;
let n2:number = Int 2;;
Example use: `to_int(n1);`
Just to be clear, there isn't a need to fill it in, and type assists helps the programmer as well, and for me in some ambiguous cases helped make sure the compiler knew what I wanted. According to my professor a few semesters ago, it is a good practice to explicitly mention it to keep types in check.