(* Copyright (c) 2006-2016, Wojciech Jaworski
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without 
 * modification, are permitted provided that the following conditions are met:
 * 
 * 1. Redistributions of source code must retain the above copyright notice, 
 * this list of conditions and the following disclaimer.
 * 
 * 2. Redistributions in binary form must reproduce the above copyright notice, 
 * this list of conditions and the following disclaimer in the documentation 
 * and/or other materials provided with the distribution.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS "AS IS" AND ANY EXPRESS 
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 
 * THE POSSIBILITY OF SUCH DAMAGE.
 *)

let iter list f = List.iter f list
let fold list s f = List.fold_left f s list
let map list f = List.map f list
let rev_map list f = List.rev_map f list

let iter2 list list2 f = List.iter2 f list list2
let fold2 list list2 s f = List.fold_left2 f s list list2
let map2 list list2 f = List.map2 f list list2

let rec iter3 list1 list2 list3 f =
  match list1,list2,list3 with
    [],[],[] -> ()
  | x1 :: l1, x2 :: l2, x3 :: l3 -> (f x1 x2 x3; iter3 l1 l2 l3 f)
  | _ -> invalid_arg "List.iter3"

let size = List.length

let tl = List.tl
let hd = List.hd

let mem l e = List.mem e l

let sort l c = List.sort c l

let filter l f = List.filter f l

let assoc l s = List.assoc s l

(* 'a list list -> 'a list list *) 
(* [[a1;a2;...;an];[b1;b2;...;bk];[c1;c2;...;cn]] -> [[a1;b1;c1];[a1;b1;c2];...;[a1;b1;cn];[a1;b2;c1];...] *)
let rec multiply_list = function
    [] -> [[]]
  | x :: list ->
      let list = multiply_list list in
      fold x [] (fun mul a ->
	fold list mul (fun mul args ->
	  (a :: args) :: mul))

