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.
Related
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.
Haven't been able to find much online documentation regarding begin/end in ocaml. I have two different pattern matches in the same function (which I want to be independent of each other), but vscode is parsing them to nest the second inside the first. I've tried surrounding the first pattern match in begin/end, but it's giving me syntax errors:
begin match c.r with (* first pattern match *)
| [ r1; r2; r3 ] ->
let _ = print_endline (String.make 1 r3.top) in end
match cl with (* second pattern match *)
| [] -> []
I get a red underline on end that says Syntax error after unclosed begin, expecting expr. I do not understand what this means, since I wrote end to close the begin, so why is the begin unclosed? The code compiles fine without the begin/end (except that it nests the second pattern match inside the first one). Thanks.
In OCaml begin/end is essentially identical to open/close parentheses. Inside you should have a well-formed expression (as in pretty much any programming language).
What you have inside your begin/end is not an expression, since it ends wih in. A let expression looks like let pattern = expr1 in expr2. You are missing the second expression inside the begin/end.
What you should do (I think) is put begin/end around the inner match like this:
match c.r with
| [r1; r2; r3 ] ->
let _ = print_endline (String.make 1 r3.top) in
begin
match c1 with
| [] -> []
...
end
| ...
(This code doesn't make a lot of sense but I assume it's just an example.)
As another simplification you can change let _ = a in b to a; b if a is of unit type, as it is in your code.
What Jeffrey Scofield said. Consider how this can become confusing when we nest matches. How do we read the following?
match "foo" with
| "bar" -> 42
| "foo" ->
match "baz" with
| "baz" -> 27
| _ -> 19
| _ -> 33
The indentation makes it fairly clear how this is meant, but OCaml doesn't care about your pretty indentation. It could just as easily be that you meant:
match "foo" with
| "bar" -> 42
| "foo" ->
match "baz" with
| "baz" -> 27
| _ -> 19
| _ -> 33
Or:
match "foo" with
| "bar" -> 42
| "foo" ->
match "baz" with
| "baz" -> 27
| _ -> 19
| _ -> 33
Either parentheses or begin/end disambiguate this situation.
match "foo" with
| "bar" -> 42
| "foo" ->
(match "baz" with
| "baz" -> 27
| _ -> 19)
| _ -> 33
Or:
match "foo" with
| "bar" -> 42
| "foo" ->
begin
match "baz" with
| "baz" -> 27
| _ -> 19
end
| _ -> 33
One more thing...
Nested match expressions are often unnecessary. Consider when you have a nested match if you can't more cleanly express the same as a single level match on a tuple of values.
match a with
| X -> ...
| Y ->
(match b with
| Z -> ...
| W -> ...
| _ -> ...)
| U ->
(match c with
| F -> ...
| G -> ...
| _ -> ...)
| _ -> ...
vs.
match a, b, c with
| X, _, _ -> ...
| Y, Z, _ -> ...
| Y, W, _ -> ...
| Y, _, _ -> ...
| U, _, F -> ...
| U, _, G -> ...
| U, _, _ -> ...
| _, _, _ -> ...
I don't have much experience with ocmal and the compiler error message isn't very helpful. I don't see any obvious problem with the code. I have the full code and the error message below. Thank you.
Full compiler error message:
File "compile.ml",
| Id(x) ->
^^
Error: This variant pattern is expected to have type prim1
The constructor Id does not belong to type prim1
type reg =
| EAX
| ESP
type arg =
| Const of int
| Reg of reg
| RegOffset of int * reg
type instruction =
| IMov of arg * arg
| IAdd of arg * arg
| IRet
type prim1 =
| Add1
| Sub1
type expr =
| Number of int
| Prim1 of prim1 * expr
| Let of (string * expr) list * expr
| Id of string
let rec find (ls : (string * int) list) (x : string) =
match ls with
| [] -> None
| (y,v)::rest ->
if y = x then Some(v) else find rest x
let rec compile_env (p : expr) (stack_index : int) (env : (string * int) list) : instruction list =
match p with
| Number(n) -> [ IMov(Reg(EAX), Const(n)) ]
| Prim1(op, e) ->
match op with
| Add1 -> (compile_env e stack_index env) # [ IAdd(Reg(EAX), Const(1)) ]
| Sub1 -> (compile_env e stack_index env) # [ IAdd(Reg(EAX), Const(-1)) ]
| Id(x) ->
match find env x with
| None -> failwith "%s not in scope" x
| Some value -> [IMov(Reg(EAX), RegOffset(value, Reg(ESP)))]
| Let(binds, body) ->
match binds with
| [] -> [] # (compile_env body stack_index env)
| (str, exp)::rest ->
let new_env = env # [(str, -4*stack_index)] in
let eval_expr = (compile_env exp stack_index env) in
let eval_tail = (compile_env Let(rest, body) stack_index+1 new_env) in
eval_expr # [IMov(RegOffset(-4*stack_index, Reg(ESP)), Reg(EAX))] # eval_tail
It looks like your problem is that you have nested match expressions. The difficulty is that the compiler is thinking that the next case of the outer match is in fact the next case of the inner match.
The solution is to parenthesize all of the the inner match expressions.
It should look something like this:
match p with
| Number(n) -> [ IMov(Reg(EAX), Const(n)) ]
| Prim1(op, e) ->
(match op with
| Add1 -> (compile_env e stack_index env) # [ IAdd(Reg(EAX), Const(1)) ]
| Sub1 -> (compile_env e stack_index env) # [ IAdd(Reg(EAX), Const(-1)) ]
)
. . .
You need to do this for all of the nested match expressions (I see 3 of them).
This is the description of warning 27 from the OCaml manual:
27 Innocuous unused variable: unused variable that is not bound with let nor as, and doesn't start with an underscore (_) character.
This warning is turned on by jbuilder --dev, and I'm curious to know in which cases people find it useful. For me, it's an annoyance to get warnings when I write code like this:
$ utop -w +27
utop # fun (x, y) -> x;;
Characters 8-9:
Warning 27: unused variable y.
- : 'a * 'b -> 'a = <fun>
or like that:
utop # let error loc msg = failwith (loc ^ ": " ^ msg);;
val error : string -> string -> 'a = <fun>
utop # let rec eval = function
| `Plus (loc, a, b) -> eval a + eval b
| `Minus (loc, a, b) -> eval a - eval b
| `Star (loc, a, b) -> eval a * eval b
| `Slash (loc, a, b) ->
let denom = eval b in
if denom = 0 then
error loc "division by zero"
else
eval a / denom
| `Int (loc, x) -> x
;;
Characters 33-36:
Warning 27: unused variable loc.
Characters 73-76:
Warning 27: unused variable loc.
Characters 112-115:
Warning 27: unused variable loc.
Characters 287-290:
Warning 27: unused variable loc.
val eval :
([< `Int of 'b * int
| `Minus of 'c * 'a * 'a
| `Plus of 'd * 'a * 'a
| `Slash of 'e * 'a * 'a
| `Star of 'f * 'a * 'a ]
as 'a) ->
int = <fun>
I know that prepending an underscore to the identifiers as in _loc suppresses the warnings, but it's not compatible with my notions that:
variables starting with an underscore are ugly and are meant for use in generated code, hidden from the programmer;
a name given to something should not have to change based on how it's used (including unused).
Using underscores, the code becomes:
(* Here we have _loc or loc depending on whether it's used. *)
let rec eval = function
| `Plus (_loc, a, b) -> eval a + eval b
| `Minus (_loc, a, b) -> eval a - eval b
| `Star (_loc, a, b) -> eval a * eval b
| `Slash (loc, a, b) ->
let denom = eval b in
if denom = 0 then
error loc "division by zero"
else
eval a / denom
| `Int (_loc, x) -> x
or
(* Here it can be hard to know what _ stands for. *)
let rec eval = function
| `Plus (_, a, b) -> eval a + eval b
| `Minus (_, a, b) -> eval a - eval b
| `Star (_, a, b) -> eval a * eval b
| `Slash (loc, a, b) ->
let denom = eval b in
if denom = 0 then
error loc "division by zero"
else
eval a / denom
| `Int (_, x) -> x
It is very useful in the monadic code, where instead of the common syntactic let bindings you're forced to use monadic >>= bind operator. Basically, where
let x = something in
code
translates to
something >>= fun x ->
code
If x is not used in code then only with the 27 warning enabled the latter will be highlighted, while the former will produce a warning by default. Enabling this warning, revealed lots of bugs for us. For example, it showed us that this code is buggy :)
Another source of use cases are higher-order functions, i.e., map, fold, etc. It captures one of the most common bugs:
let bug init =
List.fold ~init ~f:(fun acc xs ->
List.fold ~init ~f:(fun acc x -> x :: acc))
Concerning the ugliness, I totally agree that underscores are ugly, but in most cases, this is the main purpose of them - to highlight the suspicious code. Concerning the example, that you're showing, in the modern OCaml it could be easily addressed with the inline records, e.g.,
type exp =
| Plus of {loc : loc; lhs : exp; rhs: exp}
| ...
so that instead of using the underscores, you can just omit the unused field,
let rec eval = function
| Plus {lhs; rhs} -> eval lhs + eval rhs
You can use the same approach without using inline records by sparing some extra space in your program and defining all those records separately. The real-world example.
For me this warning is useful in order to remind me to explicit more my intention. If we take your example :
fun (x, y) -> x;;
Your intention is to use only the first element. If we rewrite it this way :
fun (x, _ ) -> x;;
You use a pattern matching in the parameter to make your code more concise, but you explain your intention of using only the first element. The added value in this example is small, related to the very simple implementation. But in real life functions, this warning promote a good habit in coding.
i'm trying to write an interpreter in Ocaml but I do not know resolve the error in this program:
SYNTAX
type ide = string
type exp =
| Eint of int
| Ebool of bool
| Den of ide
| Sum of exp * exp
| Diff of exp * exp
| Prod of exp * exp
| Eq of exp * exp
| Minus of exp
| Iszero of exp
| Or of exp * exp
| And of exp * exp
| Not of exp
| Ifthenelse of exp * exp * exp
| Let of ide * exp * 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*)
;;
SEMANTIC
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
;;
RUN-TIME SUPPORT
| 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(etupla) = sem(Etup(tupla), r) in
ValTup(Seq(evex1, etupla))
| 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")
and applyPipe tup argo r = match tup with
| Seq(Den f, tupla) ->
applyPipe tupla (Apply(Den f,argo)) r
| Seq(Pipe(tuplaP),tupla) ->
let appf = applyPipe tuplaP argo r in
applyPipe tupla appf r (**)
| Nil -> sem(argo,r)
| _ -> failwith("Not a valid Pipe")
;;
The error is on the line (***) : "the variant type tuple has no constructor Pipe"
How can I solve it?
The compiler expects the first argument of applyPipe to have type tuple. On the line (***) the applyPipe is applied to the value Pipe(tupla) which has type exp.