let ( let* ) o f = match o with Ok v -> f v | Error _ as e -> e
let ( let+ ) o f = match o with Ok v -> Ok (f v) | Error _ as e -> e

(* TODO use polymorphic variant for errors *)
let unwrap_err_msg o = match o with Error (`Msg e) -> Error e | Ok v -> Ok v

let list_iter f l =
  let err = ref None in
  try
    List.iter
      (fun v ->
        match f v with
        | Error _e as e ->
            err := Some e;
            raise Exit
        | Ok () -> ())
      l;
    Ok ()
  with Exit -> ( match !err with None -> assert false | Some v -> v)

let list_map f l =
  let err = ref None in
  try
    Ok
      (List.map
         (fun v ->
           match f v with
           | Error _e as e ->
               err := Some e;
               raise Exit
           | Ok v -> v)
         l)
  with Exit -> ( match !err with None -> assert false | Some v -> v)

let list_fold_left f acc l =
  List.fold_left
    (fun acc v ->
      let* acc = acc in
      f acc v)
    (Ok acc) l
