Reputation: 3919
As an academic exercise I'm trying to generate all possible permutations of a list using the OCaml language, and can't use a for-loop. I can use variables, recursion, pattern-matching, and if-else controls.
Here's what I'm thinking so far: Since I can use recursion, if I want to generate all 6 permutations of the list [1;2;3] then I could pattern-match with h::t where h is 1 and t is [2;3], and suppose that I have all permutations of [2;3]. Then I want to loop through all of these permutations of [2;3] inserting 1 in every possible coordinate: 0, 1, and 2. So for instance with [2;3] I want to generate [1;2;3] and [2;1;3] and [2;3;1], and then for [3;2] I want to generate [1;3;2] and [3;1;2] and [3;2;1].
However there are some obvious problems. One is that I need to tell the computer, with these tools, how to do insertion--but I figured that out already. I also need to "loop" over all the smaller permutations, and then loop over all their coordinates, something I'm not allowed to do. That's where I'm stuck.
Here's what I've done:
(* This successfully does insertion of v into l at pos.*)
let rec insert_at_i (v: int) (l: int list) (pos: int) : int list =
begin match (l, pos) with
| (_, 0) -> v::l
| ([], _) -> failwith "invalid insert_at_i"
| (h::t, _) -> h::(insert_at_i v t (pos - 1))
end
(* This finds the length of a list.*)
let rec len (l: int list) : int =
begin match l with
| [] -> 0
| h::t -> (1 + (len t))
end
(* Here I'm trying to take a value like 1 and a list like [2;3] and
generate the list of all lists where 1 is inserted somewhere. Since I
can't loop, I tried thinking of a way to pattern-match, but it's not
working out. I tried to make extra parameters for basically keeping
track of the recursion's results as I go, but I'm running into the
problem that in a functional language like this, variables can't be re-
written with their side-effects stored, so to speak. *)
let rec insert_ith_at_i (v: int) (l: int list) (pos: int) (sofar: int list list): int list list =
if (l = []) then [[v]]
else if (pos > (len l)) then sofar
else (insert_ith_at_i v l (pos + 1) )
Any guidance or hits are appreciated.
Upvotes: 3
Views: 1764
Reputation: 4425
Here is a solution - I define first some helper function :
let ( ^^ ) e ll = List.map (fun x -> e::x) ll
This function add one element to every list contained in a list :
1 ^^ [[2; 3]; [3; 2]] gives : [[1; 2; 3]; [1; 3; 2]]
Then the permut
function :
let rec permut l r = /* l : left, r right */
match r with
| [] -> [[]]
| [x] -> x ^^ (permut [] l)
| x::t -> let s = permut (x::l) t in
(x ^^ (permut [] (l@t))) @ s;;
permut [] [1;2;3];
The algorithm runs as follows :
Upvotes: 3