public static Opt <int> BinarySearch <element>(this IReadOnlyList <element> list, element value, IComparer <element> comparer = null, Ord fallback = default(Ord)) { if (list == null) { throw new ArgumentNullException(nameof(list)); } int lo = 0; int hi = list.Count - 1; comparer = comparer ?? Comparer <element> .Default; while (lo <= hi) { int i = lo + ((hi - lo) >> 1); int c = comparer.Compare(list[i], value); if (c == 0) { return(i); } if (c < 0) { lo = i + 1; } else { hi = i - 1; } } var fallenBack = fallback.Case(lo - 1, -1, lo); return(fallenBack.IsOnSemiInterval(0, list.Count, AInt32.Class).ThenOrDefault(fallenBack.PureOpt())); }
/// <summary> /// `Greater than` projection test /// </summary> public static bool IsGt(this Ord that) => that.Case(false, false, true);
/// <summary> /// `Less than` projection test /// </summary> public static bool IsLt(this Ord that) => that.Case(true, false, false);
/// <summary> /// `Greater than` projection /// </summary> public static Unit Gt(this Ord that) => that.Case(Failing <Unit> .Tag(that, nameof(Lt)), Failing <Unit> .Tag(that, nameof(Lt)), Id);
/// <summary> /// `Less than` projection /// </summary> public static Unit Lt(this Ord that) => that.Case(Id, Failing <Unit> .Tag(that, nameof(Lt)), Failing <Unit> .Tag(that, nameof(Lt)));
/// <summary> /// Basic pattern matcher (lazy) /// </summary> public static res Case <res>(this Ord that, Func <Unit, res> Lt, Func <Unit, res> Eq, Func <Unit, res> Gt) => that.Case <Func <Unit, res> >(Lt, Eq, Gt).ToValue();
/// <summary> /// Basic pattern matcher /// </summary> public static res Case <res>(this Ord that, res Lt, res Eq, res Gt) => that.Case(Lt, Fst, Eq, Fst, Gt, Fst);
/// <summary> /// From well-order to neg/zero/pos integer /// </summary> public static int ToInt(this Ord that) => that.Case(-1, 0, 1);