Hacker News new | ask | show | jobs
by leif 5719 days ago
Re: 8, you don't need decorators to compose functions:

    def comp(f, g):
        def h(*args, **kwargs):
            return g(f(*args, **kwargs))
        # fix up h.__doc__ and friends
        return h
or simply

    (lambda the, args: g(f(the, args))(x, y)
(don't remember comp's semantics, is (comp f g) = f o g or g o f?)

too long; don't read:

Decorators are certainly cool, but semantically they represent something more like a pattern than a FP construct. A decorator represents something you might want to do to lots of functions, a property you want all instances of a function to have without writing it explicitly into each function. Function composition is more along the lines of having two functions which are interesting on their own, but which sometimes you want to compose.

With decorators, it would also be awkward to compose multiple functions. Observe:

    def compose_with(g):
        def decorator(f):
            def decorated_function(*args, **kwargs):
                return g(f(*args, **kwargs))
            return decorated_function
        return decorator

    def h(x): math.sqrt(x)

    @compose_with(h)
    def g(x): 2 * x

    @compose_with(g)
    def f(x): x + 1
versus (for some reasonable definition of apply...)

    def compose(*fns):
        def composition(*args, **kwargs):
            return reduce((lambda computed, next_fn: next_fn.apply(computed)),
                          fns,
                          (args, kwargs))
        return composition

    # define fns as above without decorator
    hogof = compose(f, g, h)
1 comments

To expand on what I was thinking with #8, here's how I'd implement a decorator in Clojure

(def my-decor (partial comp decor-bevior))

Done.

Well, what python calls a "decorator" is just a function that accepts a function and returns a function with roughly similar functionality. In python, the old way to decorate functions was

    def my_decorator(f): ...
    def my_function(...): ...
    my_function = my_decorator(my_function)
and the new "@my_decorator" syntax is just sugar for this.

Function composition is only one of many things you can do with decorators. You could implement a K-combinator with them if you wanted to:

    def kestrel(x):
        "decorates a function to evaluate that function, but then return x"
        def decorator(f):
            def g(*args, **kwargs):
                f(*args, **kwargs)
                return x
            return g
        return decorator

    @kestrel(4)
    def foo(x):
        y = x + 1
        print y
        return y

    foo(5) # => 4, but prints 6