Can I define a "rec" function in another "rec" function in Ocaml? - function

I must make a function isFunction that takes a list of couples as an argument and return true if there is no repetition considering the first element in each couple and false if there is a repetition.
For example :isFunction [(1,3);(2,40);(3,40)] returns true but isFunction [(1,3);(2,40);(1,40)] returns false because 1 is repeated.
For now, my code is :
let rec exist e = function
|[] -> false
|(a,_)::l -> e=a || exist e l;;
let rec isFunction = function
|[]->true
|(a,_)::l -> not(exist a l) && isFunction l;;
which works perfectly! But the question is : is there another way to define isFunction without defining another auxiliary function?

You can declare exist as local to isFunction:
let rec isFunction l =
let rec exist e = function
|[] -> false
|(a,_)::l -> e=a || exist e l
in
match l with
|[]->true
|(a,_)::l -> not(exist a l) && isFunction l

You can use List.exists :
let isFunction = function
| [] -> true
| (a,_)::tl -> not (List.exists (fun (a',_) -> a'=a) tl) && isFunction l;;

Related

What is wrong with this code for creating lists in OCaml?

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 []

Implement the functions using map and foldr, haskell

I have two functions. The first one gives true if all elements of the list are zero
allZero :: [Int] -> Bool
allZero [] = False
allZero [0] = True
allZero (x:xs)
| x == 0 && allZero xs = True
|otherwise = False
The second function gives true if at least one element of the list is zero
oneZero :: [Int] -> Bool
oneZero [] = False
oneZero (x:xs)
| x == 0 = True
| otherwise = oneZero xs
Maybe there is another way to solve this problems. For example with map or foldr?
Thank you
foldr function works so:
Suppose, you have list [1, 2, 3]. Let's write this list as (:) 1 ((:) 2 ((:) 3 [])), where each element has type a. Function foldr takes function f of a -> b -> b type and starting element z of b type, and just replace [] to z and : to f. So, foldr f z ((:) 1 ((:) 2 ((:) 3 []))) == f 1 (f 2 (f 3 z)).
So, you can define your functions so:
allZero = foldr (\x -> x == 0 &&) True
oneZero = foldr (\x -> x == 0 ||) False
foldr basically takes your guard as its folding function:
allZero = foldr (\x acc -> x == 0 && acc) True
acc (for accumulator) is the already-computed value of the recursive call. Being right-associative, the first non-zero value in the list short-circuits the evaluation of the fold function on the rest of the list.
(Note that allZero [] == True by convention. The "hypothesis" is that allZero xs is true, with evidence in the form of a non-zero element to falsify the hypothesis. No elements in the list, no evidence to contradict the hypothesis.)
I leave it as an exercise to adapt this to compute oneZero.

Recursive call in if expression - ocaml

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)

Why one parameter Ocaml function works with two arguments

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

OCaml - Save values of recursive function in hashtable

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