How can I pass a constructor as an arg and then pattern match on it? - ocaml

e.g.
let expect_raises f exc =
try f ()
with
| exc -> "Expected error raised"
| e -> "Unexpected error raised"
in
expect_raises (fun () -> raise Not_found) Not_found (* "Expected" *)
expect_raises (fun () -> raise Invalid_argument "bad") Not_found (* "Unexpected" *)
But this doesn't work because I can't pattern match on the exc arg, it just becomes the pattern variable.
Is there some way to do this?

Pattern matching in OCaml works essentially against constants (or more generally trees of constants with wildcard slots). So there's no way to use pattern matching to do what you want. This is the same for exceptions as it would be if you (for example) wanted to pass an integer value.
Similarly to integers, you can compare exception values for equality. So you can write your function like this:
let expect_raises f exc =
try f ()
with e ->
if e = exc then "Expected error raise"
else "Unexpected error raised"
Here are the test cases:
# expect_raises (fun () -> raise Not_found) Not_found;;
- : string = "Expected error raise"
# expect_raises (fun () -> raise (Invalid_argument "bad")) Not_found;;
- : string = "Unexpected error raised"
However, this seems like a fragile test because the equality comparison depends on the exact contents of the exception constructor. The compiler warns (reasonably so IMHO) against doing this:
# match (try failwith "abc" with e -> e) with
| Failure "abc" -> 20
| _ -> 30;;
Warning 52 [fragile-literal-pattern]: Code should not
depend on the actual values of this constructor's
arguments. They are only for information and may change
in future versions. (See manual section 11.5)

FWIW my solution at the moment looks like:
let expect_raises f exc_f pp =
let result_opt =
try exc_f f
with e -> Some (Error e)
in
match result_opt with
| Some (Ok a) ->
fail ## Format.asprintf "Unexpected result: %a" pp a
| Some (Error e) ->
fail ## Printf.sprintf "Unexpected error: %s" (Printexc.to_string e)
| None -> pass (* the correct result *)
let test_fun () ->
let exc_f f = try Some (Ok (f ())) with Not_found -> None in
expect_raises (fun () -> funtotest 123) exc_f pp
let test_other_fun () ->
let exc_f f = try Some (Ok (f ())) with Invalid_argument _ -> None in
expect_raises (fun () -> otherfuntotest "abc") exc_f pp
Having to define the exf_f is a bit cumbersome - I would love to be able to factor out the common part leaving just the exception type. But at least this works and allows to match by constructor alone and not by value.
I guess it would be possible to make a ppx rewriter to replace manual definition of exc_f func with something like:
expect_raises (fun () -> otherfuntotest "abc") [%excf Invalid_argument] pp

Related

Is this use of Obj.magic necessary?

I am reading a repository and I encountered this function in the body of some Yojson json parsing code:
let load_problems channel =
let open Yojson.Basic.Util in
let j = Yojson.Basic.from_channel channel in
...
let rec unpack x =
try magical (x |> to_int) with _ ->
try magical (x |> to_float) with _ ->
try magical (x |> to_bool) with _ ->
try
let v = x |> to_string in
if String.length v = 1 then magical v.[0] else magical v
with _ ->
try
x |> to_list |> List.map ~f:unpack |> magical
with _ -> raise (Failure "could not unpack")
in
...
where magical = Obj.magic. I understand what Obj.magic is (it's the equivalent to Unsafe.Coerce in Haskell), but I don't see why a type coercion is necessary here. The Yojson.Basic.Util functions the author uses should already either succeed or fail to do this conversion. Any intuition?
EDIT:
I feel I was depriving #glennsl of context, so here is the immediately following passage in which unpack is used:
let tf = j |> member "tasks" |> to_list |> List.map ~f:(fun j ->
let e = j |> member "examples" |> to_list in
let task_type = j |> member "request" |> deserialize_type in
let examples = e |> List.map ~f:(fun ex -> (ex |> member "inputs" |> to_list |> List.map ~f:unpack,
ex |> member "output" |> unpack)) in
let maximum_frontier = j |> member "maximumFrontier" |> to_int in
let name = j |> member "name" |> to_string in
let task =
(try
let special = j |> member "specialTask" |> to_string in
match special |> Hashtbl.find task_handler with
| Some(handler) -> handler (j |> member "extras")
| None -> (Printf.eprintf " (ocaml) FATAL: Could not find handler for %s\n" special;
exit 1)
with _ -> supervised_task) ~timeout:timeout name task_type examples
in
(task, maximum_frontier))
in
There are a number of different task_handlers, but the one I happen to be concerned with is defined as follows:
(fun extras ?timeout:(timeout = 0.001) name ty examples ->
let open Yojson.Basic.Util in
let cost_matters =
try
extras |> member "costMatters" |> to_bool
with _ -> assert false
in
let by = match examples with
| [([0],y)] ->
Bigarray.(Array1.of_array int8_unsigned c_layout (Array.of_list y))
| [([1],y)] ->
Bigarray.(Array1.of_array int8_unsigned c_layout (Array.of_list y))
| _ -> failwith "not a turtle task" in
{ name = name ;
task_type = ty ;
log_likelihood =
(fun p ->
try
match run_recent_logo ~timeout p with
| Some(bx,cost) when (LogoLib.LogoInterpreter.fp_equal bx by 0) ->
(if cost_matters then (0.-.cost)*.10. else 0.)
| _ -> log 0.
with (* We have to be a bit careful with exceptions if the
* synthesized program generated an exception, then we just
* terminate w/ false but if the enumeration timeout was
* triggered during program evaluation, we need to pass the
* exception on
*)
| UnknownPrimitive(n) -> raise (Failure ("Unknown primitive: "^n))
| EnumerationTimeout -> raise EnumerationTimeout
| _ -> log 0.0)
});;
The author also uses ;; in a lot of files..another quirk.

Ocaml user-defined type pattern matching

Here is my type definition:
type ('type1, 'type2) symbol =
| N of 'type1
| T of 'type2
Here are some types:
type mysub =| Abc | Bcd | Def
I also have a list [N Abc;N Bcd; T"("].
What I want to do is that throw away all items of type T, and also throw away 'type1 or 'type2. So the desired result is [Abc; Bcd]
But when I try this piece of code:
List.map (fun x-> match x with N (a)->a |T (b) ->b ) (List.filter (fun x->match x with
N (type1) ->true |T (type2) -> false) [N Abc;N Bcd; T"("]);;
it gives me the following message:
Error: This expression has type (mysub, string) symbol list
but an expression was expected of type
(mysub, mysub) symbol list
Type string is not compatible with type mysub.
How can I fix it?
In this fragment
List.map
(fun x -> match x with
N a -> a
T b -> b
)
The return types aren't the same for the two match cases. If there were any T b elements in the list, the b would be a string, and the compiler doesn't know there aren't any such elements. Since you know there aren't any, you could fix this by supplying something other than b as the result for that case. Something like this:
List.map
(fun x -> match x with
N a -> a
T _ -> Abc
)
Or even this:
List.map
(fun x -> match x with
N a -> a
T _ -> failwith "This can't happen"
)

Ocaml Exceptions With Try Catch

I need to create a function that generates an exception in certain cases but I need it to generate a certain error using try catch. It uses functions :
let lookup (x,evn) = match listAssoc(x,evn) with
|Some Int v ->Int v
| None -> raise (MLFailure "variable not found")
;;
let arithmetic (x,y,z) = match (x,y,z) with
| (Int a, Int b, Plus)-> Int (a+b)
| (Int a, Int b,Minus) -> Int (a-b)
| (Int a, Int b, Mul)-> Int (a*b)
| (Int a, Int b, Div)-> Int (a/b)
;;
This is the function:
let errorlookup (x,evn) = match listAssoc(x,evn) with
| Some Int v ->Int v
| None -> raise (Nano.MLFailure "variable not found %s" x)
;;
let rec eval (evn,e) = match e with
| Const a -> Int a
| Var x-> (lookup (x,evn) )
| Bin( expr1, Plus, expr2) -> arithmetic(eval(evn,expr1),eval(evn,expr2),Plus)
|Bin( expr1, Minus,expr2) -> arithmetic(eval(evn,expr1),eval(evn,expr2),Minus)
|Bin( expr1, Mul, expr2) -> arithmetic(eval(evn,expr1),eval(evn,expr2),Mul)
| Bin( expr1, Div, expr2) -> arithmetic(eval(evn,expr1),eval(evn,expr2),Div)
;;
I need to make sure that in the Var x case, when lookup result is None I need to print an Exception
# eval (evn, Var "p");;
Exception: MLFailure "variable not bound: p".
eval evaluates an expression with a current environment, for example
let evn = [("z1",Int 0);("x",Int 1);("y",Int 2);("z",Int 3);("z1",Int 4)];;
val evn : (string * Nano.value) list =
[("z1", Int 0); ("x", Int 1); ("y", Int 2); ("z", Int 3); ("z1", Int 4)]
I made the types for Bin and Val and Expr but those arent relevant to this.
I need to raise an exception based on the result of lookup but not raise the exception that is in lookup. Someone suggested using try catch but I'm not sure how that would work for OCaml and this. This was the hint given by TA:
lookup should throw the following exception:
raise (MLFailure "not found")
Whereas eval should throw the following one:
# eval (evn, Var "p");;
Exception: MLFailure "variable not bound: p".
It seems that you've to do exception handling here. You can use the
try <expression> with
| <exception> -> <handler>
syntax to catch & handle exceptions inside eval.
It's not clear what you're asking. But I suspect your TA has told you what you need to know. You can read about the OCaml try ... with expression in Section 6.7 of the OCaml manual. This is the OCaml equivalent to try ... catch of some other languages.
If you want to catch a particular exception but let others propagate as usual, you just need to match the one you're interested in:
try
<expression1>
with Not_found -> <expression2>
If you have complicated requirements, you can match several different exceptions, and after the match you can compute values and/or re-raise exceptions.
try
<expression1>
with
| Not_found -> raise (MLFailure "abc")
| Divide_by_zero -> max_int
| _ -> raise (Invalid_argument "def")

Extracting data from a tuple in OCaml

I'm trying to use the CIL library to parse C source code. I'm searching for a particular function using its name.
let cil_func = Caml.List.find (fun g ->
match g with
| GFun(f,_) when (equal f.svar.vname func) -> true
| _ -> false
) cil_file.globals in
let body g = match g with GFun(f,_) -> f.sbody in
dumpBlock defaultCilPrinter stdout 1 (body cil_func)
So I have a type GFun of fundec * location, and I'm trying to get the sbody attribute of fundec.
It seems redundant to do a second pattern match, not to mention, the compiler complains that it's not exhaustive. Is there a better way of doing this?
You can define your own function that returns just the fundec:
let rec find_fundec fname = function
| [] -> raise Not_found
| GFun (f, _) :: _ when equal (f.svar.vname fname) -> f (* ? *)
| _ :: t -> find_fundec fname t
Then your code looks more like this:
let cil_fundec = find_fundec func cil_file.globals in
dumpBlock defaultCilPrinter stdout 1 cil_fundec.sbody
For what it's worth, the line marked (* ? *) looks wrong to me. I don't see why f.svar.vname would be a function. I'm just copying your code there.
Update
Fixed an error (one I often make), sorry.

OCaml: finally clause related issues

type 'a result =
Success of 'a
| Failed of exn
let finally f x cleanup =
let result =
try Success (f x) with
exn -> Failed exn
in
cleanup ();
match result with
Success y -> y
| Failed exn -> raise exn
There are several places I do not understand:
the syntax of finally
exn is a type, how can we use it in a pattern matching? Failed exn?
Success (f x) matched with exn?
relationship between cleanup and f x.
It is supposed that use will use finally something like that:
let h = open_db () in
let f db = ... return someting from db in
let res = finally f h (fun () -> close_db h) in
exn is a type but name spaces for types and values are almost not mixing in OCaml. So, when you write Failed exn exn is name binding
Success (f x) is not returned if exception raises during evaluation f x.
x is resource which you should free in finally branch, f does some work with created x