ocaml begin/end pattern matching - ocaml

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, _, _ -> ...
| _, _, _ -> ...

Related

Trying to create a function to transform list of strings into 1 string and add spaces between words

let rec createSentence(list) = (
match list with
case [] -> failwith "błędna lista"
| case [_] -> List.hd list
| case [_,_] -> List.hd list ^ createSentence(List.tl list)
| case _ -> List.hd list ^ " " ^ createSentence(List.tl list);;
);;
Ocaml returns a Syntax error: operator expected. I have no idea how to move forward with this
The pattern-matching in OCaml has the following syntax,
match <expr> with
| <pattern1> -> <action1>
| <pattern2> -> <action2>
...
e.g.,
match ["hello"; "world"] with
| [word1; word2] -> print_endline (word1 ^ word2)
| _ -> assert false
Also, note that the list elements in OCaml are separated with ;
I would suggest reading the Introduction to OCaml or some OCaml book
Update: to make it more clear, there is no case keyword in OCaml and you shouldn't write case before a pattern, i.e., instead of | case [], just write | [].

Error: This variant pattern is expected to have type prim1. The constructor Id does not belong to type prim1

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).

Interpreter with Ocaml

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.

Syntax error in OCaml evaluation function

I found this code to evaluate expressions in OCaml on the internet and want to try to understand how it works, but when I enter it in my editor and run it I get the following error:
type t =
| Integer of int
| Binary of binary * t * t
and binary =
| Add
| Sub
| Mult
| Div
type token =
| INTEGER of int
| ADD
| SUB
| MULT
| DIV
let rec eval = function
| Integer(k) -> k
| Binary(op, a, b) ->
(match op with
| Add -> ( + )
| Sub -> ( - )
| Mult -> ( * )
| Div -> ( / )) (eval a) (eval b)
let lexer s =
let open Str in
let split s =
let rec splitchar x l =
if x< 0 then l else splitchar (x-1) ( s.[x]:: l ) in
splitchar ( String.length s -1) []
|> List.map
(function
| "+" -> ADD
| "-" -> SUB
| "*" -> MULT
| "/" -> DIV
| _ -> failwith "lexer: Invalid token: %s" );;
Characters 280-282:
| _ -> failwith "lexer: Invalid token: %s" );;
^^
Error: Syntax error
The error message doesn't help very much and I've tried a few changes that only make things worse. Can anyone help me get started by figuring out what the syntax error is?
There is a couple of issues :
split is defined but not used.
failwith expects a string, not a format.
For the first issue : you have to use split before List.map:
...in split s | List.map...
failwith expect a string, in the current case, the mistake is that it is a string that looks more a format string that waits for another string.
The fix is as below :
- first catch the string
- then use it to form the final string expected by failwith
(function
| "+" -> ADD <br>
| "-" -> SUB <br>
| "*" -> MULT <br>
| "/" -> DIV <br>
| _ as s -> failwith ("lexer: Invalid token: " ^ s) );;
But I am not sure at all the whole code will work....

How to check in the next 'head' in OCaml is empty?

I'm new at OCaml (and still a novice in learning programming in general) and I have a quick question about checking what kind of string the next element in the string list is.
I want it to put a separator between each element of the string (except for the last one), but I can't figure out how to make the program 'know' that the last element is the last element.
Here is my code as it is now:
let rec join (separator: string) (l : string list) : string =
begin match l with
| []->""
| head::head2::list-> if head2=[] then head^(join separator list) else head^separator^(join separator list)
end
let test () : bool =
(join "," ["a";"b";"c"]) = "a,b,c"
;; run_test "test_join1" test
Thanks in advance!
You're almost there. The idea is breaking down the list in three cases where it has 0, 1 or at least 2 elements. When the list has more than one element, you're safe to insert separator into the output string:
let rec join (separator: string) (l : string list) : string =
begin match l with
| [] -> ""
| head::[] -> head
| head::list-> head^separator^(join separator list)
end
I have several comments about your function:
Type annotation is redundant. Because (^) is string concatenation operator, the type checker can infer types of separator, l and the output of the function easily.
No need to use begin/and pair. Since you have only one level of pattern matching, there is no confusion to the compiler.
You could use function to eliminate match l with part.
Therefore, your code could be shortened as:
let rec join sep l =
match l with
| [] -> ""
| x::[] -> x
| x::xs -> x ^ sep ^ join sep xs
or even more concise:
let rec join sep = function
| [] -> ""
| x::[] -> x
| x::xs -> x ^ sep ^ join sep xs
The empty list is [], the list with one element is [h] and the list with at least one element is h::t. So your function can be written as:
let rec join separator = function
| [] -> ""
| [h] -> h
| h::t -> h ^ separator ^ join separator t