I was trying out some of the exercises in a dune build. I think my issue is due to the semicolons but I'm not really sure. When running the following code:
let somelist = [1;2;3;4] in
(* last element in a list *)
match (last somelist) with
| Some (v) ->
print_endline "last value of list:" ;
print_int v;
| None -> () ;
print_newline ();
(* last 2 elements in a list *)
match (last_two somelist) with
| Some (a::b) ->
print_endline "last 2 elements in list: \n";
print_int a;
print_int (List.hd b);
| None -> () ;
| Some ([]) -> () ;;
print_newline () ;;
it only prints out:
last value of list:
4
instead of continuing and printing out the last 2 elements in the list afterwards. I tested out the other 2 functions, last and last_two in utop and they seem to work.
I wanted it to print out:
last value of list:
4
last 2 elements in list:
3 4
Each branch of a match contains a list of expressions separated by ; (or at least this is one way to describe the syntax). So your second match is contained within just one of the branches of the first match. I.e., it executes only if last somelist is None.
The usual way to solve this is by enclosing the first match in begin / end or parentheses. Here's one way to do this:
begin
match (last somelist) with
| Some (v) ->
print_endline "last value of list:" ;
print_int v;
| None -> ()
end;
print_newline ();
match (last_two somelist) with
. . .
Related
For a better understanding, I try to rewrite this code without "... with" but I struggle:
let rec blast list =
list with
| x :: y :: [] -> x
| hd :: tl -> blast tl
| _ -> fail "not enough";;
Any ideas? Thanks!
Sure we could "manually" try to match each pattern.
The first applies when there is exactly 2 elements, the second when there is more than 1 (but not 2) and the third in all other cases (0 elements).
The second case can be folded into the last case (As when there is 1 element, the recursive call just fails).
So now we have 3 cases: exactly 2, more than 2 and less than 2.
Perfect for List.compare_length_with: 'a list -> int -> int:
let rec beforelast list =
let cmp = List.compare_length_with list 2 in
if cmp = 0 then (* Exactly 2 elements *)
List.hd list
else if cmp > 0 then (* More than 2 elements *)
beforelast (List.tl list)
else (* 1 or 0 elements *)
failwith "not enough"
Though note that you are still pattern matching under the hood, because that's what OCaml data types are made for. For example, List.hd might be implemented like:
let hd = function
| head :: _ -> head
| [] -> raise (Failure "hd")
So the match ... with way should be the way that leads to a better understanding.
As I was typing up some code in OCaml, I wanted to match two cases at once (since the function I'm writing is commutative):
type something =
| Two of int * int
| One of int
let my_function p q =
match p, q with
| Two (_, _) as two, One (x)
| One (x), Two (_, _) as two -> (* some value *)
| _ -> (* some other value *)
;;
I'm getting the following error:
Error: Variable two must occur on both sides of this | pattern
The problem doesn't occur when I remove the as statement, but I need it for the logic purposes. Why can't I do it like this? Will I have to resort to rewriting the logic twice?
as has lower precedence than ,. Hence you should put parenthesis around Two (_,_) as two.
I would like to create a basic genetic algorithm in order to output a set of input to enter in an emulator. Basically, what it does is :
Generate an input sheet
List item
Run said input
slightly modify it
Run it
See whichever input set performed better and "fork" it and repeat until the problem is solved
So : here is my code to generate the first set of inputs :
(* RNG initialization
* unit *)
Random.self_init();;
(* Generating a starting input file
* array
* 500 inputs long *)
let first_input =
let first_array = Array.make 500 "START" in
for i = 1 to 499 do
let input =
match Random.int(5) with
| 0 -> "A "
| 1 -> "B "
| 2 -> "DOWN "
| 3 -> "LEFT "
| 4 -> "RIGHT "
| _ -> "START " in
first_array.(i) <- input
done;
first_array;;
And here is my "mutation" function that randomly alters some inputs :
(* Mutating input_file
* Rate : in percent, must be positive and <= 100
* a must be an array of strings *)
let mutation a n=
let mutation_rate = n in
for i = 0 to ((Array.length(a) * mutation_rate / 100) - 1) do
let input =
match Random.int(5) with
| 0 -> "A "
| 1 -> "B "
| 2 -> "DOWN "
| 3 -> "LEFT "
| 4 -> "RIGHT "
| _ -> "START " in
a.( Random.int(498) + 1) <- input
done;;
However, I don't feel like my function is efficient because I had to paste the pattern matching part in the mutation function and I think there has to be a smarter way to proceed. If I define my "input" function as a global function, then it is only evaluated once (let's say as "RIGHT" and all occurrences of "input" will return "RIGHT" which is not really useful.
Thanks.
There isn't anything wrong with putting that into it's own function. What you are missing is an argument to make the function deal with the side-effect of Random.int. Since you are not using this argument, it's often/always the case people use unit.
let random_input () = match Random.int 5 with
| 0 -> "A "
| 1 -> "B "
| 2 -> "DOWN "
| 3 -> "LEFT "
| 4 -> "RIGHT "
| _ -> "START "
What you are doing here is pattern matching the argument, and since there is only one constructor this matching is exhaustive. But technically, you can replace the () above with an _. This will match anything making the function polymorphic against it's argument, 'a -> string. In this case it's bad form since it may lead to confusion as to what the parameter is for.
So this is a merge sort function I'm playing with in OCaml. The funny thing is the code delivers what I expect, which means, it sorts the list. But then raises some errors. So can someone please check my code and tell me what's going on and why these errors? And how do I eliminate them? I'm a OCaml newbie but I really want to get what's going on:
(* Merge Sort *)
(* This works but produces some extra error. Consult someone!! *)
let rec length_inner l n =
match l with
[] -> n
| h::t -> length_inner t (n + 1)
;;
let length l = length_inner l 0;;
let rec take n l =
if n = 0 then [] else
match l with
h::t -> h :: take (n - 1) t
;;
let rec drop n l =
if n = 0 then l else
match l with
h::t -> drop (n - 1) t
;;
let rec merge x y =
match x, y with
[], l -> l
| l, [] -> l
| hx::tx, hy::ty ->
if hx < hy
then hx :: merge tx (hy :: ty)
else hy :: merge (hx :: tx) ty
;;
let rec msort l =
match l with
[] -> []
| [x] -> [x]
| _ ->
let left = take (length l/2) l in
let right = drop (length l/2) l in
merge (msort left) (msort right)
;;
msort [53; 9; 2; 6; 19];;
In the terminal, I get:
OCaml version 4.00.1
# #use "prac.ml";;
val length_inner : 'a list -> int -> int = <fun>
val length : 'a list -> int = <fun>
File "prac.ml", line 13, characters 2-44:
Warning 8: this pattern-matching is not exhaustive.
Here is an example of a value that is not matched:
[]
val take : int -> 'a list -> 'a list = <fun>
File "prac.ml", line 19, characters 2-39:
Warning 8: this pattern-matching is not exhaustive.
Here is an example of a value that is not matched:
[]
val drop : int -> 'a list -> 'a list = <fun>
val merge : 'a list -> 'a list -> 'a list = <fun>
val msort : 'a list -> 'a list = <fun>
- : int list = [2; 6; 9; 19; 53]
#
The compiler is telling you that your pattern matches aren't exhaustive. In fact it's telling exactly what to try to see the problem. For example, you might try:
drop 2 []
To fix the problem you need to decide what to do with empty lists in your functions. Here's a definition of drop with exhaustive matches:
let rec drop n l =
if n = 0 then l
else
match l with
| [] -> []
| h::t -> drop (n - 1) t
If this isn't clear: your code doesn't say what to do with an empty list. Your matches only say what to do if the list has the form h :: t. But an empty list doesn't have this form. You need to add a case for [] to your matches.
I want to replace a sublist lista with another sublist listb from a list listo to achieve the following result:
let replace_sublist listo lista listb =
In listo , if there is a sublist = lista, then replace this sublist with listb.
I found a similar question implemented in python.
Link:
Replacing a sublist with another sublist in python
Any suggestion? Thanks.
type 'a strip_result =
| No_match
| Too_short
| Tail of 'a list
(** [try_strip li subli] tries to
remove the prefix [subli] from the list [li] *)
let rec try_strip li subli = match li, subli with
| _, [] -> Tail li
| [], _ -> Too_short
| hli::tli, hsub::tsub ->
if hli <> hsub then No_match
else try_strip tli tsub
let rec replace_sublist li from_sub to_sub =
match li with
| [] -> []
| head::tail ->
match try_strip li from_sub with
| Too_short -> li
| No_match -> head :: replace_sublist tail from_sub to_sub
| Tail rest -> to_sub # replace_sublist rest from_sub to_sub
let test =
(* simple replace *)
assert (replace_sublist [1;2;3;4] [2;3] [-2;-3] = [1;-2;-3;4]);
(* multiple replace *)
assert (replace_sublist [1;2;3;2;4] [2] [0] = [1;0;3;0;4]);
(* stop while partial match *)
assert (replace_sublist [1;2;3;4] [3;4;5] [0] = [1;2;3;4]);
(* stop at match *)
assert (replace_sublist [1;2;3;4] [3;4] [2;1] = [1;2;2;1]);
(* tricky repeating sublist case *)
assert (replace_sublist [2;2;3] [2;3] [0] = [2;0]);
()
(* tail-rec version: instead of concatenating elements before
the recursive call
head :: replace_sublist ...
to_sub # replace_sublist ...
keep an accumulator parameter `acc` to store the partial result,
in reverse order
replace (t :: acc) ...
replace (List.rev_append to_sub acc) ...
*)
let replace_sublist li from_sub to_sub =
let rec replace acc li = match li with
| [] -> List.rev acc
| head::tail as li ->
match try_strip li from_sub with
| Too_short -> List.rev (List.rev_append li acc)
| No_match -> replace (head :: acc) tail
| Tail rest -> replace (List.rev_append to_sub acc) rest
in replace [] li
PS: it is well-known that this algorithm can be improved by moving, after try_strip failed, not just to the next element in the list but by some number of elements that we know cannot start a new match. However, this number of elements to jump over is not something simple like List.length from_sub - 1, it needs to be precomputed from the pattern structure (it depends from the presence of "tricky repeating sublists"). This is the Knuth-Morris-Pratt algorithm.
You can do something like that :
let replace listo lista listb =
let rec loop listo lista listb accu =
match listo with
[] -> List.rev accu
| x :: xs ->
if xs = lista then List.rev_append (x :: accu) listb
else loop xs lista listb (x :: accu) in
loop listo lista listb []
First you need to find the sublist lista. Once you find this list, you can just revert the accumulator accu and then append the listb
This is essentially a substring search and replace. If your lists are long, you might want to use a fancy algorithm like Knuth-Morris-Pratt to avoid a quadratic number of comparisons.
(I was going to write some code, bug gasche already did an excellent job.)