let hd v = match v with
    h :: t -> h
  | [ ] -> failwith "hd"

let tl v = match v with
    h :: t -> t
  | [ ] -> failwith "tl"

let rec map f l =
	if l = [] then []
	else f (hd l) :: map f (tl l)
	
let rec fold_left f a l =
	if l = [] then a
	else fold_left f (f a (hd l)) (tl l)
	
let rec fold_right f l a =
	if l = [] then a
	else f (hd l) (fold_right f (tl l) a)

let rec append l1 l2 =
	if l1 = [] then l2
	else hd l1 :: append (tl l1) l2

let rec rev_append l1 l2 =
	if l1 = [] then l2
	else rev_append (tl l1) (hd l1 :: l2)

let rev l = rev_append l []
	
let rev_append' l1 l2 =
	while l1 != [] do
		l2 := hd l1 :: l2;
		l1 := tl l1
	done;
	l2

let rev' l = rev_append' l []
	
let rec flatten = function
  [ ] -> [ ]
| h :: t -> append h (flatten t)

let rec length l =
	if l = [] then 0
	else length (tl l) + 1
	
let length' l =
	let n = 0 in
	while l != [] do
		n := n + 1;
		l := tl l
	done;
	n

let rec assoc a l = match l with
  [ ] -> print a; failwith "Not_found"
| (k, v) :: t -> (if a = k then v else (assoc a t))

let rec remove_assoc a l = match l with
  [] -> []
| (k, v) :: t -> let tr = remove_assoc a t in
  if a = k then tr else (k, v) :: tr

let rec string_concat s l = match l with
  [ ] -> ""
| [ a ] -> a
| h :: t -> (h ^ s ^ (string_concat s t))

let rec sort comp l =
  let rec split l = match l with
    | [] -> [], []
    | [h] -> [h], []  
    | h1 :: h2 :: t -> (
      match split t with t1, t2 -> h1 :: t1, h2 :: t2) in
  let rec merge l1 l2 = match l1, l2 with
    | [], l2 -> l2
    | l1, [] -> l1
    | h1 :: t1, h2 :: t2 ->
      if comp h1 h2 <= 0 then h1 :: (merge t1 l2)
      else h2 :: (merge l1 t2)
  in match l with [] -> [] | [a] -> [a] 
     | l -> (match split l with l1, l2 ->
    	     merge (sort comp l1) (sort comp l2))	
    
type 'a option = None | Some of 'a

let rec assoc_option a l = match l with
  [ ] -> None
| (k, v) :: t -> (if a = k then Some v else (assoc_option a t))

let fst p = match p with (a, b) -> a
let snd p = match p with (a, b) -> b


