def square(x): return x * x
def smallest_divisor(n):
    return find_divisor(n, 2)

def find_divisor(n, test_divisor):
    return (n if square(test_divisor) > n
            else test_divisor if divides(test_divisor, n)
            else find_divisor(n, test_divisor + 1))

def divides(a, b):
    return b % a == 0
def is_prime(n):
    return n == smallest_divisor(n)
def inc(n):
    return n + 1
def gcd(a, b):
    return a if b == 0 else gcd(b, a % b)
def filtered_accumulate(combiner, null_value,
                        term, a, next, b, filter):
    return (null_value if a > b
            else combiner(term(a),
                          filtered_accumulate(combiner, null_value,
                                              term, next(a), next,
                                              b, filter)) if filter(a)
            else filtered_accumulate(combiner, null_value,
                                     term, next(a), next,
                                     b, filter))

def prime_squares_sum(a, b):
    def plus(x, y):
        return x + y
    return filtered_accumulate(plus, 0,
                               square, a, inc, b,
                               is_prime)

def relative_prime_product(n):
    def times(x, y):
        return x * y
    def identity(x):
        return x
    def test(i):
        return gcd(i, n) == 1
    return filtered_accumulate(times, 1,
                               identity, 1, inc, n,
                               test)

print(prime_squares_sum(4, 10))  # 74
# relative_prime_product(8)  # 105

# expected: 74
