I want to choose n
distinct random elements in a list l
and return them in choose_elements
but I have a StackOverFlow
error for sufficiently large lists!
I tried to use a tail_recursive function choose_elem_aux
in order to do that but I think my condition List.mem
is not efficient enough in term of complexity!
I do this normally in other programming languages with a boolean mark array which I mark the index of each random number that is generated in true
!
But I can't do this in OCaml because I can't do multiple instruction into an if or else block! like this:
... else {
mark[r] =true ;
choose_elem_aux l n mark tmp ;
} ...
let choose l =
nth l (Random.int (List.length l)) ;;
let rec choose_elem_aux l n tmp =
if n=0 then tmp
else
let r=choose l in
if List.mem r tmp then
choose_elem_aux l n tmp
else
choose_elem_aux l (n-1) (r::tmp) ;;
let rec choose_elements l n =
choose_elem_aux l n [] ;;
StackOverflow for large list like:
choose_elements [1...10_000] 7 ;;
First of all, ocaml does allow you to write several statements in an if then else
, it's just not written as in C-like languages.
if condition then begin
instruction1 ;
instruction 2 ;
(* ... *)
end
else begin
(* ... *)
end
The begin (* ... *) end
block works the same as parentheses, so you can also just parenthesise:
if condition then (
instruction1 ;
instruction 2 ;
(* ... *)
)
else (
(* ... *)
)
So you can do your optimisation just fine.
What happens here is that when writing if b then t else f
in ocaml, you are building a value of type T
if t : T
and f : T
.
You can for instance write if b then 0 else 1
or if b then "Hello" else "Goodbye"
.
It also works with the unit
type (the type of most instructions):
if b then instruction1 else instruction2
The semicolon operator allows to do two instructions sequentially:
(;) : unit -> unit -> unit
Note that it is not the same as in most language where it marks the end of an instruction.
The problem is that when you write
if b then instruction1 else instruction2 ; instruction 3
it is not understood as
if b then instruction1 else (instruction2 ; instruction 3)
as you wished, but as
(if b then instruction1 else instruction2) ; instruction 3
which also makes sense because the if
expression also has type unit
.