def stream_tail(stream):
    return tail(stream)()
def memo(fun):
    already_run = False
    result = None
    def memoized():
        nonlocal already_run, result
        if not already_run:
            result = fun()
            already_run = True
            return result
        else:
            return result
    return memoized
def stream_map_2(f, s1, s2):
    return (None
            if is_none(s1) or is_none(s2)
            else pair(f(head(s1), head(s2)),
                      lambda: stream_map_2(f, stream_tail(s1), stream_tail(s2))))

def stream_map_2_optimized(f, s1, s2):
    return (None
            if is_none(s1) or is_none(s2)
            else pair(f(head(s1), head(s2)),
                      memo(lambda: stream_map_2_optimized(f, stream_tail(s1), stream_tail(s2)))))

ints1 = integers_from(1)
ints0 = integers_from(0)
adds = lambda x, y: x + y

display(eval_stream(stream_map_2(adds, ints1, ints0), 5))
print(display(eval_stream(stream_map_2_optimized(adds, ints1, ints0), 5)))
