Correction de Jill-Jênn

(* https://jill-jenn.net/tp/1-recursivite-listes.pdf *)
(* TL;DR Q6 pour faire flatten, on pouvait utiliser fold_left *)
(*       Q9 pour faire nb_occ, on pouvait utiliser filter et list_length *)

(* Question 1. *)

let rec fibo0 n = match n with
	| 0 -> 0
	| 1 -> 1
	| n -> fibo0 (n - 1) + fibo0 (n - 2)
;;

(* La complexité de la fonction est exponentielle. *)

let fibo n = aux 0 1 n where
	rec aux a b c = if c == 0 then a else aux b (b + a) (c - 1)
;;

(* Question 2. *)

let rev1 l = aux l [] where
	rec aux l1 l2 = match l1 with
		| [] -> l2
		| h::t -> aux t (h::l2)
;;

(* Question 3. *)

let map1 f l = aux [] l where
	rec aux r l = match l with
		| [] -> rev r
		| h::t -> aux (f h::r) t
;;

(* Question 4. *)

let filter p l = aux [] l where
	rec aux r l = match l with
		| [] -> r
		| h::t -> if p h then aux (h::r) t else aux r t
;;

(* Question 5. *)

let fold_left f a l = aux a l where
	rec aux r l = match l with
		| [] -> r
		| h::t -> aux (f r h) t
;;

(* Question 6. *)

let rec flatten l = match l with
	| [] -> []
	| h::t -> fold_left (fun x y -> y::x) (flatten t) (rev h)
;;

(* Question 7. *)

let fibogen f0 f1 op n = aux f0 f1 n where
	rec aux a b c = if c == 0 then a else aux b (op b a) (c - 1)
;;

let fibo = fibogen 0 1 prefix +;;

(* Question 8. *)

let fiboword = fibogen "b" "a" prefix ^;;
let fibolist = fibogen [1] [0] prefix @;;

(* Question 9. *)

let nb_occ x0 l = list_length (filter (function x -> x == x0) l);;

(* Question 10. *)

let tronque n l = aux n (rev l) where
	rec aux n l = match n with
		| 0 -> rev l
		| n -> try aux (n - 1) (tl l) with Failure _ -> []
;;

(* Question 11. *)

let rec ajoute l1 l2 = match l1 with
	| [] -> l2
	| h::t -> ajoute t (h::l2)
;;

let remplace x lx l = aux [] l where
	rec aux r l = match l with
		| [] -> rev r
		| h::t -> if h == x then aux (ajoute lx r) t else aux (h::r) t
;;

remplace 2 [0] (remplace 0 [0;1] (remplace 1 [2] [0;1;0]));;

(* Bonus gratuit *)

let remplace_multi subst l = aux [] l where
	rec aux r l = match l with
		| [] -> rev r
		| h::t -> try let remp = assoc h subst in aux (ajoute remp r) t with Not_found -> aux (h::r) t
;;

remplace_multi [0,[0;1];1,[0]] [0;1;0];;

(* Question 12. *)

(* Version récursive non terminale *)

let rec exp1 a n = match n with
	| 0 -> 1
	| n when n mod 2 == 0 -> let u = exp1 a (n / 2) in u * u (* S *)
	| n -> let u = exp1 a (n / 2) in u * u * a (* SM *)
;;

(* Version récursive terminale *)

let exp2 a n = aux 1 a n where
	rec aux p a n = match n with
		| 0 -> p
		| n when n mod 2 == 0 -> aux p (a * a) (n / 2)
		| n -> aux (p * a) (a * a) (n / 2)
;;

(* Question 13. *)

type op = S | M;;

let sm_of_exp n = aux [] n where
	rec aux l n = match n with
		| 0 -> l
		| n when n mod 2 == 0 -> aux (S::l) (n / 2)
		| n -> aux (S::(M::l)) (n / 2)
;;

(* Question 14. *)

let decode l = aux 0 l where
	rec aux n l = match l with
		| [] -> n
		| _::(false::t) -> aux (n * 2 + 1) t
		| _::t -> aux (n * 2) t
;;