let usage args = let err = Format.sprintf "usage: %s %s" Sys.argv.(0) args in print_endline err; exit 1 let usage_default day = usage (string_of_int day ^ " ") let main day mains = function | [part; input] -> mains.(int_of_string part - 1) input | _ -> usage_default day type 'a monoid = {id: 'a; op: 'a -> 'a -> 'a; op_name: string; pp: Format.formatter -> 'a -> unit} let mult = {id = 1; op = ( * ); op_name = "*"; pp = Format.pp_print_int} let add = {id = 0; op = ( + ); op_name = "+"; pp = Format.pp_print_int} let fold_list {op; id; _} = List.fold_left op id let%test _ = fold_list add [] = 0 let%test _ = fold_list add [1;2;3;4] = 10 let%test _ = fold_list mult [1;2;3;4] = 24 let print_fold ?(format=false) mon xs = let res = List.fold_left mon.op mon.id xs in let rec go fmt = function | [] -> Format.fprintf fmt "%a" mon.pp mon.id | [x] -> Format.fprintf fmt "%a" mon.pp x | x::xs -> let f = if format then Format.fprintf fmt "%a %s@ %a" else Format.fprintf fmt "%a %s %a" in f mon.pp x mon.op_name go xs in let f = if format then Format.printf "%a =@ %a\n" else Format.printf "%a = %a\n" in f go xs mon.pp res let print_prod ?format = print_fold ?format mult let print_sum ?format = print_fold ?format add let%expect_test _ = print_prod []; [%expect{| 1 = 1 |}] let%expect_test _ = print_prod [1]; [%expect{| 1 = 1 |}] let%expect_test _ = print_prod [1;2;3;4]; [%expect{| 1 * 2 * 3 * 4 = 24 |}] let%expect_test _ = print_sum []; [%expect{| 0 = 0 |}] let%expect_test _ = print_sum [1]; [%expect{| 1 = 1 |}] let%expect_test _ = print_sum [1;2;3;4]; [%expect{| 1 + 2 + 3 + 4 = 10 |}]