Steven D'Aprano wrote:
> Sent: Sunday, 16 August, 2009 08:15
>
> On Sat, 15 Aug 2009 04:39:03 am Jason R. Coombs wrote:
>
> >
> > def meta_decorator(data):
> >     return compose(dec_register_function_for_x, dec_alter_docstring,
> >     dec_inject_some_data(data))
>
> Surely that's better written as:
>
> meta_decorator = compose(dec_register_function_for_x,
>     dec_alter_docstring, dec_inject_some_data)

I agree. The former looks unnecessarily complicated.

I purposely chose a non-trivial use case, one which involves a decorator that 
requires a parameter and thus must be called first before the actual decorator 
is returned.  I think for this reason, the former syntax must be used so that 
the meta_decorator also takes the data parameter and constructs the proper 
"inject" decorator.  Put another way, both dec_inject_some_data and 
meta_decorator are more like decorator factories.

I suspect a simpler, and more common use-case would be like the one you 
described, where either data is global or the "inject" decorator is not used:

meta_decorator = compose(dec_register_function_for_x, dec_alter_docstring)

>
> Mine wasn't -- I've never even used Scheme, or Lisp, or any other
> functional language. But I've come to appreciate Python's functional
> tools, and would like to give a +0.5 to compose(). +1 if anyone can
> come up with additional use-cases.

Thanks for the interest.  I decided to search through some of my active code 
for lambdas and see if there are areas where I would prefer to be using a 
compose function instead of an explicit lambda/reduce combination.

I only found one such application; I attribute this limited finding to the fact 
that I probably elected for a procedural implementation when the functional 
implementation might have proven difficult to read, esp. with lambda.

1) Multiple string substitutions.  You have a list of functions that operate on 
a string, but you want to collect them into a single operator that can be 
applied to a list of strings.

sub_year = lambda s: s.replace("%Y", "2009")

fix_strings_with_substituted_year = compose(str.strip, textwrap.dedent, 
sub_year)
map(fix_strings_with_substituted_year, target_strings)

Moreover, it would be great to be able to accept any number of substitutions.

substitutions = [sub_year, sub_month, ...]
fix_strings_with_substitutions = compose(str.strip, textwrap.dedent, 
*substitutions)



I did conceive of another possibly interesting use case: vector translation.

Consider an application that performs mathematical translations on 
n-dimensional vectors.  While it would be optimal to use optimized matrix 
operations to perform these translations, for the sake of this example, all we 
have are basic Python programming constructs.

At run-time, the user can compose an experiment to be conducted on his series 
of vectors. To do this, he selects from a list of provided translations and can 
provide his own.  These translations can be tagged as named translations and 
thereafter used as translations themselves.  The code might look something like:

translations = selected_translations + custom_translations
meta_translation = compose(*translations)
save_translation(meta_translation, "My New Translation")

def run_experiment(translation, vectors):
        result = map(translation, vectors)
        # do something with result

Then, run_experiment can take a single translation or a meta-translation such 
as the one created above. This use-case highlights that a composed functions 
must take and return exactly one value, but that the value need not be a 
primitive scalar.



I'm certain there are other, more obscure examples, but I feel these two use 
cases demonstrate some fairly common potential use cases for something like a 
composition function.

Jason
_______________________________________________
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com

Reply via email to