def compose(self, function): """Creates a Function as composition of ``function`` with ``self``. Function composition: >>> f = Function(lambda a: -a).compose(abs) >>> f(-1) -1 Function composition operator ``**``: >>> f = Function(lambda a: -a) ** abs >>> f(-1) -1 ``**`` works on either side, no need to wrap both sides: >>> f = Function(list) ** map << 1 .__add__ >>> f(range(10)) [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] >>> f = list ** Function(map) << 1 .__add__ >>> f(range(10)) [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] """ return self.clone(compose(self.invoke, self.clone(function)))
def pipe(self, function): """Creates a Function that pipes output into ``function`` if invoked. Piping output: >>> f = Function(range).pipe(sum).pipe(int.__neg__) >>> f(1, 101) -5050 Pipe operator ``|``: >>> f = Function(range) | sum | int.__neg__ >>> f(1, 101) -5050 >>> f = Function(map) << 1 .__add__ | list >>> f(range(10)) [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] >>> sum_upto = 1 .__add__ | Function(range) << 1 | sum >>> sum_upto(100) 5050 """ return self.clone(compose(function, self.invoke))
def test_compose(): identity = lambda a: a # Left identity f = int g = compose(identity, f) assert f('42') == g('42') for n in range(42): # this number is not significant here. assert f(n) == g(n) # Right identity f = str g = compose(f, identity) assert f(42) == g(42) for n in range(42): # this number is not significant here. assert f(n) == g(n) # Associative # NOTE: these functions are specifically chosen, so that when composed in # different orders, yield different outputs. f = hash g = str h = type f1 = compose(f, compose(g, h)) f2 = compose(compose(f, g), h) ns = [42, 0.5, '42', sum, f, lambda: 0] for n in ns: # make sure these functions yield different outputs when composed in # different order, assert f1(n) != compose(f, compose(h, g))(n) assert f2(n) != compose(f, compose(h, g))(n) assert f1(n) != compose(g, compose(f, h))(n) assert f2(n) != compose(g, compose(f, h))(n) assert f1(n) != compose(g, compose(h, f))(n) assert f2(n) != compose(g, compose(h, f))(n) assert f1(n) != compose(h, compose(g, f))(n) assert f2(n) != compose(h, compose(g, f))(n) assert f1(n) != compose(h, compose(f, g))(n) assert f2(n) != compose(h, compose(f, g))(n) # but compose should obey associative law. assert f1(n) == f2(n)