return x else: return f(Thunk([f, x, tail(copy(xs))]).bind(apply(fold)), head(copy(xs))) @curry def map(f, xs): return xs.map(lambda xs: map(f, xs)) @curry def filter(f, xs): return xs.map(lambda xs: filter(f, xs)) def do(exp, **kwargs): load = Thunk({}) def loadKeypair(k, v): return v.map(lambda v: {k: v}) def apply(load, k, v): load.bind(lambda ls: loadKeypair(k, v).map(lambda p: dict(ls, **p))) for k, v in kwargs.iteritems(): apply(load, k, v) return load.bind(lambda ls: exp(**ls)) @curry def add(a, b): return do(lambda a, b: Thunk(a + b), a=a, b=b) assert unroll(lambda me, a, b: add(a, b))(Thunk(1), Thunk(2)) == 3 assert unroll(lambda me: fold(add, Thunk(0), Thunk([1,2,3])))() == 6
def match(x, p): return p(unroll(lambda me: x)())
def assertThunksEqual(self, a, b): thunk1 = unroll(lambda me: a)() thunk2 = unroll(lambda me: b)() self.assertEqual(thunk1, thunk2)