def stream_tail(stream):
    return tail(stream)()
def stream_ref(s, n):
    return (head(s)
            if n == 0
            else stream_ref(stream_tail(s), n - 1))

def stream_map(f, s):
    return (None
            if is_none(s)
            else pair(f(head(s)),
                      lambda: stream_map(f, stream_tail(s))))

def stream_for_each(fun, s):
    if is_none(s):
        return True
    else:
        fun(head(s))
        return stream_for_each(fun, stream_tail(s))
def stream_filter(pred, stream):
    return (None
            if is_none(stream)
            else pair(head(stream),
                      lambda: stream_filter(pred, stream_tail(stream)))
            if pred(head(stream))
            else stream_filter(pred, stream_tail(stream)))
def square(x): return x * x
def is_divisible(x, y):
    return x % y == 0
def integers_starting_from(n):
    return pair(n, lambda: integers_starting_from(n + 1))
def is_prime(n):
    def iter(ps):
        return (True
                if square(head(ps)) > n
                else False
                if is_divisible(n, head(ps))
                else iter(stream_tail(ps)))
    return iter(primes)

primes = pair(2,
              lambda: stream_filter(
                          is_prime,
                          integers_starting_from(3)))
def interleave(s1, s2):
    return (s2
            if is_none(s1)
            else pair(head(s1),
                      lambda: interleave(s2, stream_tail(s1))))
def pairs(s, t):
    return pair(llist(head(s), head(t)),
                lambda: interleave(stream_map(lambda x: llist(head(s), x),
                                              stream_tail(t)),
                                   pairs(stream_tail(s),
                                         stream_tail(t))))
integers = integers_starting_from(1)
max_display = 9
def display_stream(s):
    def display_stream_iter(st, n):
        if is_none(st):
            pass
        elif n == 0:
            display("", "...")
        else:
            display(head(st))
            display_stream_iter(stream_tail(st), n - 1)
    display_stream_iter(s, max_display)
int_pairs = pairs(integers, integers)
print(stream_ref(stream_filter(lambda pair: is_prime(head(pair) + head(tail(pair))),
              int_pairs), 8))

# expected: [ 1, [ 12, null ] ]
