let convert a b a_to_b b_to_a =
  if a.num_bits <= b.num_bits then
    ((fun i -> Some (a_to_b i)), a_to_b)
  else
    let { min = b_min; max = b_max; name = b_name } = b in
    let min = b_to_a b_min in
    let max = b_to_a b_max in
    let compare = a.compare in
    let is_in_range i = compare min i <= 0 && compare i max <= 0 in
    let convert i = if is_in_range i then Some (a_to_b i) else None in
    let { name = a_name; to_string = a_to_string } = a in
    let convert_exn i =
      if is_in_range i then
        a_to_b i
      else
        Core_printf.failwithf
          "conversion from %s to %s failed: %s is out of range"
          a_name b_name (a_to_string i) ()
    in
    convert, convert_exn