[Tutor] Text processing and functional programming?

Danny Yoo dyoo at hkn.eecs.berkeley.edu
Thu Aug 14 16:24:02 EDT 2003



> Yes, they come from Haskell most directly but the concept of
> comprehensions exists in the math too.
>
> > > avoid the intimidating keyword "lambda", but oh well.  *grin*
>
> But lambda is the intuitive name for anyone who has loked at the math.
> If you have studied the lamda calculus any other name would seem totally
> bizarre! A lambda is a lambda, thats its name. Its like deciding to call
> a tuple a 'bunch' just because you hadn't heard the term tuple used
> before...


Hi Alan,


There is historical precedent to giving the 'lambda' operator a different
name, though.  The OCaml folks, for example, use the keyword 'function' to
create anonymous functions:

(*** OCaml ***)
# let square = function x -> x * x;;
val square : int -> int = <fun>
# square 42;;
- : int = 1764
(*************)

I just personally feel that when the lambda concept was introduced into
Python, that 'function' would have been a better keyword than 'lambda'.
Just an opinion, though, and not that big of a deal.




> What I refer to is the ability to generate a list of functions using a
> comprehension:
>
> >>> numbers = [2,5,9]
> >>> multipliers = [lambda x,y=z: y*x for z in numbers]
> >>> for n in range(3):
> ...    print multipliers[n](7)
> ...
> 14
> 35
> 63



The heart of functional programming, I think, isn't really map() or
filter(), but the ability to create and handle dynamic functions like
these --- to be able to play with functions just like strings or numbers.

It might be worthwhile to give another slightly more realistic example of
closures.  Here's another example, writing a set of functions to generate
HTML code:

###
>>> def make_tagger(tag_name):
...     def tag_function(content):
...         return "<%s>%s</%s>" % (tag_name, content, tag_name)
...     return tag_function
...
>>>
>>>
>>> p, h1, h2, i, b = map(make_tagger, ['p', 'h1', 'h2', 'i', 'b'])
>>>
>>>
>>> p("Hello, this is a test, "
...   + i("italicized") + " and " + b("bolded!"))
'<p>Hello, this is a test, <i>italicized</i> and <b>bolded!</b></p>'
###


Again, this code is a oversimplified, but it hints at the kind of power we
have with closures.  Of course, we can do all of this without having to
using any mapping or closure or FP technique:


###
def p(content):
    return "<p>%s</p>" % content

def h1(content):
    return "<h1>%s</h1>" % content

# etc...
###

but that's just dull code: why not let Python do most of this work?
*grin*



One other advantage about this approach is that it allows us to localize
our changes: we may later want to make sure that all of the content within
our tags are entity-escaped.  With the closure approach, we just need to
modify our make_tagger()  function:

###
>>> import xml.sax.saxutils
>>> def make_tagger(tag_name):
...     def tag_function(content):
...         return "<%s>%s</%s>" % (tag_name,
...                                 xml.sax.saxutils.escape(content),
...                                 tag_name)
...     return tag_function
...
>>>
>>> p = make_tagger('p')
>>>
>>> p("Hello, this is a test.  1 < 2")
'<p>Hello, this is a test.  1 &lt; 2</p>'
###


All our tag-generating functions then gain the benefit of proper HTML
escaping, because all of them are the offspring of make_tagger().  This is
a case where the extra indirection is a big win.



Hope this helps!




More information about the Tutor mailing list