def bisect_left(func, val, low, high):
    """
    Like bisect.bisect_left, but works on functions.

    Return the index where to insert item x in list a, assuming a is sorted.

    The return value i is such that all e in a[:i] have e < x, and all e in a[i:] have e >= x.  So if x already appears
    in the list, a.insert(x) will insert just before the leftmost x already there.  Optional args lo (default 0) and hi
    (default len(a)) bound the slice of a to be searched.

    >>> bisect_left([1,2,3,3,4].__getitem__, 3, 0, 4)
    2
    >>> bisect_left([1,2,3,3,4].__getitem__, 4, 0, 4)
    4
    >>> bisect_left([1,2,3,6,8].__getitem__, 4, 0, 4)
    3
    """

    a = low
    b = high
    while b > a:
        guess = (a+b)//2

        if val > func(guess):
            a = guess+1
        else:
            b = guess

    return a