I have this function:
let rec som a b acc =
if a > b then acc else
som (a+1) b (acc+(comb b a));;
And what I am trying to do is to save acc value in a hashtable, so my first try was:
let rec som a b acc =
if a > b then acc else
som (a+1) b (acc+(comb b a)) Hashtbl.add a acc;;
but it does not work... How can I save the values?
This is skeleton, you can try to add you code into it to get what you want. Maybe it will be helpful.
module Key = struct
type t=int
let compare: t->t->int = fun a b -> (* return -1 if a<b, 0 if a=b,and 1 if a>b *)
let equal = (=)
end
module H=Hashtbl.Make(Key)
let som =
let h = H.create () in
let rec f a b acc =
try H.find h acc
with Not_found ->
let ans = (* your evaluation code *) in
H.add h acc ans;
ans
in
f
First, let's take a look at the signature of Hashtbl.add
('a, 'b) Hashtbl.t -> 'a -> 'b -> unit = <fun>
The first argument of the function is an hash table, then you need to create one. To do it, write let h_table = Hashtbl.create 123456;;. And to put it in context your add instruction become HashTbl.add h_table a acc
Next, you can't call this function at the same level of the recursive call. Indeed the function som take three arguments and you will face the following error message, It is applied to too many arguments ....
And as you want to trace the value of acc you need to put it before the recursive call. Doing this can lead you to face some difficulty, then I've added below a hint.
let _ = Printf.printf "a\n" in
let _ = Printf.printf "b\n" in
(1+2)
;;
a
b
- : int = 3
Related
I am trying to create a program in OCaml [randlist len max], which would generate an int list of length len with integers smaller than max.
I am wondering what is wrong with the following code:
let randlist dolzina maksimum =
let rec aux dolz maks acc =
match (List.length acc) with
| dolz -> acc
| _ -> aux dolz maks ((Random.int maks) :: acc)
in
aux dolzina maksimum []
This always returns an empty list and I do not understand why.
Another thing that confuses me is what goes wrong with the following code:
let randlist dolzina maksimum =
Random.self_init ()
let rec aux dolz maks acc =
match (List.length acc) with
| dolz -> acc
| _ -> aux dolz maks ((Random.int maks) :: acc)
in
aux dolzina maksimum []
As soon as I add the Random.self init () the whole code crashes. What exactly does Random.self_init do, when and how do I use it?
You are using match as if it is going to compare two integer values, but that's not how it works. This match:
Match List.length acc with
| dolz -> ...
Will always match the first case. The name dolz is a new variable that is bound to the length of the list. The outer definition of dolz is not relevant here, a pattern introduces new names.
If you want to compare two integer values, you should use if:
if List.length acc = dolz then
...
else
...
Pattern matching deconstructs values that match a pattern into smaller parts, it doesn't test equality. In other words, your first case
match List.length acc with
| dolz -> acc
reads: take the value returned by List.length acc, name it dolz in the right hand side of the arrow ->, and run the code after ->. Notice that this means that dolz matches any values.
This is why the compiler warns you that the second case
| _ -> aux dolz maks ((Random.int maks) :: acc)
is never used.
For your second question, the code cannot crash, since your code is not well-typed and thus cannot compile. Random.self_init initialize the seed of the PRNG. You should call it once in your program, and not at every calls of randlist.
What you're trying to accomplish can be implemented without having to calculate the length of the accumulated list. You just need to count the length parameter down by one on each iteration and return acc when it is less than or equal to 0.
let randlist count max =
let rec aux c m acc =
if c <= 0 then acc
else aux (c-1) m (Random.init max :: acc)
in
aux count max []
Of course, all of this is just a convoluted way to write:
let randlist count max =
List.init count (fun _ -> Random.int max)
Here the List.init function takes care of the iteration for us. Implementing an equivalent function may shed some light on how it works.
let list_init n f =
let rec list_init' n f acc =
if n <= 0 then acc
else list_init' (n-1) f (f (n-1) :: acc)
in
list_init' n f []
I would like to print a meaningful message when raising a defined exception in OCaml:
type t = A | B of int
exception Wrong of t
Say I have a function
let string_of_t = function
| A -> "A"
| B n -> ("B" ^ (string_of_int n))
Then I would like to have a function
val print_exception : ( 'a -> string ) -> a' exn -> string
so that I can define
let my_raise e =
print_endline ("Error: I got the unexpected value" ^ (print_exception string_of_t e));
raise e [???]
Is there such a function print_exception ?
The problem is not very well-posed (for instance, there is no a' exn type), but I hope my intent is understandable. I've seen that one can use [##deriving sexp] but this looks like some magic outside of the language, and there is probably something easier and within the language.
There are two ways. The first one is using Printexc, the second one would be to match all the exceptions you want to print and print accordingly, something like:
exception Zero of int
exception B of string
let pp ppf = function
| Zero d -> Format.fprintf ppf "Zero of %d" d
| B s -> Format.fprintf ppf "B of %s" s
| Not_found -> Format.fprintf ppf "Not found"
| _ -> Format.fprintf ppf "Your exception is in another castle"
let f n d = if d = 0 then raise (Zero d) else n / d
let () =
let n, d = (10, 0) in
try Format.printf "%d/%d is %d#." n d (f n d)
with e ->
Format.eprintf "%a#." pp e;
Format.eprintf "%s#." (Printexc.to_string e)
Will give
❯ ./exc
Zero of 0
Exc.Zero(0)
Combining the two seems to be the best solution to be able to customise some displays and let all the others be a default one:
let pp ppf = function
| Zero d -> Format.fprintf ppf "Zero of %d" d
| e -> Format.fprintf ppf "%s" (Printexc.to_string e)
In OCaml we don't have (yet) modular implicits so unless you use [##derive ...] you need to use one of the two solutions.
As a side-note, exceptions can be caught in a pattern matching:
let () =
let n, d = (10, 0) in
match f n d with
| r -> Format.printf "%d/%d is %d#." n d r
| exception e ->
Format.eprintf "%a#." pp e;
Format.eprintf "%s#." (Printexc.to_string e)
It does semantically the same as what I wrote before but it's better for call stacks (if I'm not mistaken)
[EDIT] Looks like I forgot a third solution, see #octachron's answer
If you want to log a meaningful message before raising, it seems to me that it might be simpler to combine the logging and exception raising in one function rather than trying to reconstruct an error message from a generic unknown exception after the fact. For instance, the following function
let log_and_raise exn fmt =
Format.kfprintf
(fun ppf -> Format.pp_print_newline ppf (); raise exn)
Format.err_formatter fmt
can be used like this
exception A of int
let test n = log_and_raise (A n) "Raising the exception (A %d)" n
and will raise the exception A n after printing the error message on stderr.
module Dfs = struct
let rec dfslsts g paths final =
let l = PrimePath.removeDuplicates (PrimePath.extendPaths g paths)
in
let f elem =
if (List.mem "%d" (List.flatten final) = false) then (dfslsts g ["%d"] (List.flatten l)::final)
else final
in
List.iter f (Graph.nodes g)
end
Error: This expression has type string but an expression was expected of type int list
This error occurred when I called dfslsts function, which is recursive, inside the if condition.
The function dfslsts returns a list of lists.
If I try to replace the complex expression in if statement to
if (List.mem "%d" (List.flatten final) = false) then "%d"
else "%d"
then I get
Error: This expression has type 'a -> string
but an expression was expected of type 'a -> unit
Type string is not compatible with type unit
at List.iter line.
How do I solve this problem and are we allowed to call a recursive function inside the if expression.
This is the definition of my graph type:
module Graph = struct
exception NodeNotFound of int
type graph = {
nodes : int list;
edges : (int * int) list;
}
let makeGraph () =
{
nodes = [];
edges = [];
}
let rec isNodeOf g n = List.mem n g.nodes
let nodes g = g.nodes
let edges g = g.edges
let addNode g n =
let nodes = n::g.nodes and edges = g.edges in
{
nodes;
edges;
}
let addEdge g (n1, n2) =
if ((isNodeOf g n1) = false) then
raise (NodeNotFound n1)
else if ((isNodeOf g n2) = false) then
raise (NodeNotFound n2)
else
let nodes = g.nodes
and edges = (n1, n2) :: g.edges in
{
nodes;
edges;
}
let nextNodes g n =
let rec findSuccessors edges n =
match edges with
[] -> []
| (n1, n2) :: t ->
if n1 = n then n2::findSuccessors t n
else findSuccessors t n
in
findSuccessors g.edges n
let rec lastNode path =
match path with
[] -> raise (NodeNotFound 0)
| n :: [] -> n
| _ :: t -> lastNode t
end
module Paths = struct
let extendPath g path =
let n = (Graph.lastNode path) in
let nextNodes = Graph.nextNodes g n in
let rec loop path nodes =
match nodes with
[] -> []
| h :: t -> (List.append path [h]) :: (loop path t)
in
loop path nextNodes
let rec extendPaths g paths =
match paths with
[] -> []
| h :: t -> List.append (extendPath g h) (extendPaths g t)
(* Given a list lst, return a new list with all duplicate entries removed *)
let rec removeDuplicates lst =
match lst with
[]
| _ :: [] -> lst
| h :: t ->
let trimmed = removeDuplicates t in
if List.mem h trimmed then trimmed
else h :: trimmed
end
Any expression can be a recursive function call. There are no limitations like that. Your problem is that some types don't match.
I don't see any ints in this code, so I'm wondering where the compiler sees the requirement for an int list. It would help to see the type definition for your graphs.
As a side comment, you almost certainly have a precedence problem with this code:
dfslsts g ["%d"] (List.flatten l)::final
The function call to dfslsts has higher precedence that the list cons operator ::, so this is parsed as:
(dfslsts g ["%d"] (List.flatten l)) :: final
You probably need to parenthesize like this:
dfslsts g ["%d"] ((List.flatten l) :: final)
I can't understand why the following function works with 2 arguments even if we declare it with one param:
let rec removeFromList e = function
h :: t -> if h=e then h
else h :: removeFromList e t
| _ -> [];;
removeFromList 1 [1;2;3];;
You're declaring it with two parameters. The syntax:
let f = function ...
can be seen as a shortcut for
let f x = match x with
So, your definition is actually:
let rec removeFromList e lst = match lst with
h :: t -> if h=e then h else h :: removeFromList e
Eventually what I want is what x represents:
let x = (something, (myfunc1 para1));;
so that when calling x, I get a tuple, but when calling (snd x) para, I will get a return value of myfunc1 para.
What I'm trying is like this:
let myfunc2 para1 para2 =
let myfunc1 para2 = ... in
( (fst para1), (myfunc1 para2) );;
And I want to call myfunc2 like this:
let x = myfunc2 para1 to get what I described above. However, what I get is just a function which when called with para1 will return a regular tuple, not a (something, function) tuple
You have a useless para2 parameter in your definition. The correct way is:
let myfunc2 para1 =
let x = ... in
let myfunc1 para2 = ... in
( x, myfunc1 );;
But it would help if we could speak about a concrete example. You are misunderstanding something obvious, but I do not know what.
Here is a concrete example. Suppose we want a function f which accepts a number n and returns a pair (m, g) where m is the square of n and g is a function which adds n to its argument:
let f n =
let m = n * n in
let g k = n + k in
(m, g)
Or shorter:
let f n = (n * n, fun k => n + k)
Now to use this, we can do:
let x = f 10 ;;
fst x ;; (* gives 100 *)
snd x ;; (* gives <fun> *)
snd x 5 ;; (* gives 15, and is the same thing as (snd x) 5 *)
Now let us consider the following bad solution in which we make the kind of mistake you have made:
let f_bad n k =
let m = n * n in
let g k = n + k in
(m, g k)
Now f_bad wants two arguments. If we give it just one, we will not get a pair but a function expecting the other argument. And when we give it that argument, it will return a pair of two integers because (m, g k) means "make a pair whose first component is the integer m and the second component is g applied to k, so that is an integer, too."
Another point worth making is that you are confusing yourself by calling two different things para2. In our definition of f_bad we also confuse ourselves by calling two different things k. The k appearing in the definition of g is not the same as the other k. It is better to call the two k's different things:
let f_bad n k1 =
let m = n * n in
let g k2 = n + k2 in
(m, g k1)
Now, does that help clear up the confusion?