Python syntax in Lisp and Scheme

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Adrian Hey

    Re: Express What, not How.

    james anderson wrote:
    [color=blue]
    > Marcin 'Qrczak' Kowalczyk wrote:[color=green]
    >> Most high level languages have anonymous functions for a reason.
    >>[/color]
    >
    > i'm just wondering if you're serious about all of this.[/color]

    I think Marcin is serious, and any Haskeller would agree I suspect.

    A good example from Haskell would be the use of lambda abstractions
    as the second argument of the monadic >>= operator. Supplying names
    for all those abstractions would be really awkward and yield highly
    unreadable code IMO.

    For those that don't like all those lambdas, Haskell's imperative style
    "do" expressions can be used instead, but only for monads. There are
    still occassions where explicit lambda's are an easier and clearer
    alternative than defining named functions.

    Regards
    --
    Adrian Hey

    Comment

    • Terry Reedy

      Re: Python syntax in Lisp and Scheme


      "Pascal Bourguignon" <spam@thalassa. informatimago.c om> wrote in
      message news:87ekxfmhhl .fsf@thalassa.i nformatimago.co m...[color=blue]
      >
      > prunesquallor@c omcast.net writes:[color=green]
      > > Since having the correct amount of whitespace is *vital* to the
      > > correct operation of a Python program, it seems that the task of
      > > maintaining it is made that much more difficult because it is only
      > > conspicuous by its absence.[/color][/color]
      [color=blue]
      > That remembers me that when the languages had significant spaces,[/color]
      the[color=blue]
      > programming was done with forms, sheets of physical paper[/color]
      preprinted[color=blue]
      > with empty spaces:[/color]
      [further idiocy snipped]

      I do believe that several Lispers have suggested that people should
      give Lisp a fair trial before rejecting it on account of parentheses
      or macros. The same goes, of course, for Python and significant
      indents/dedents. For most people who try Python, freedom from
      visually redundant fences is a feature. Those who find it a bother
      after trying are welcome to chose another language.

      What makes the comments above doubly absurd is that Lisp has as much
      or more need for 'significant spaces' as Python. Compare (1,2,3)
      versus (1 2 3). Having the "correct amount of whitespace is *vital*
      to the correct operation of a" Lisp program as much as for any other.
      Do Lispers therefore use forms? I suspect not ;-)

      Terry J. Reedy


      Comment

      • Albert Lai

        Re: Express What, not How.

        gt5163b@prism.g atech.edu (Brian McNamara!) writes:
        [color=blue]
        > I agree with your one of your overall theses, which is that we should
        > focus on the "what" rather than the "how". Where our opinions diverge,
        > however, is that I think sometimes the best way to communicate an
        > abstraction is to show the "how" inline, rather than creating a new
        > name in an attempt to capture the "what".[/color]

        There are also times when "what" and "how" are literally the same,
        which is when the "what" is a very trivial task.

        It is a very slippery slope to insist coding styles in the name of abstraction:
        - every value must have a name
        - every function or procedure must be christened
        - everything must be put in a class or object (I call this OOP - object
        obfuscation pomposity)
        - every line of code must be commented

        There is an adverse social effect (since social effect was mentioned)
        whenever an abstraction mechanism like the above ones is doctrinized.
        Programmers will begin devaluing the mechanism. If you insist on
        comments, they start writing silly comments; if you insist on naming
        things, they start giving silly names; and if you insist on classes,
        well, they start putting everything into one single class and making
        all members static and public. They start seeing the abstraction
        mechanism as a bother and stop seeing its potential benefits.

        It is when you allow some freedom of not using a mechanism that the
        the mechanism becomes valuable. (The political parallel: some people
        like to stay in their countries precisely because their laws permit
        them to leave. Once you remove that freedom, people begin to smuggle
        themselves out.)

        Now no one is suggesting to make all functions anonymous, all code
        unstructured, and all aspects uncommented. Nothing of that sort! In
        practice we give names to all non-trivial functions. Someone asserted
        that we should judge a mode of expression for what it does when put in
        good use, not what it could do when abused. That person should not
        argue against anonymous functions by noting all the gory details of
        implementation it might expose in the wrong hands.

        And now I would like to sidetrack a bit and give an unrelated example
        of Brian's point that sometimes "what" without "how" is completely
        unclear.

        I have an abstract data type to present you. This exercise is to test
        how well you understand the "what" presentation, so the names of the
        operations will not give you a clue. They are meaningful names though
        - meaningful to me, a Cantonese speaker. (Just to show you how
        meaningless the whole notion of "meaningful names" is.) But I will
        present you "what" it does without mentioning "how".

        It is a functional (immutable) abstract data type, so most operations
        take an existing instance as a parameter and return a new instance.
        The name of the abstract data type is LiDui.

        Hung : LiDui
        MoYun : LiDui -> Bool
        PaiDui: (LiDui,Object) -> LiDui
        DuiTau: LiDui -> Object
        LeiDui: LiDui -> LiDui

        MoYun(Hung) is true.
        For any LiDui d:
        If MoYun(d) is true, we have LeiDui(PaiDui(d ,o))=d and DuiTau(PaiDui(d ,o))=o.
        If MoYun(d) is false, we have LeiDui(PaiDui(d ,o))=PaiDui(Lei Dui(d),o).

        That's it.

        I have never seen any first-year CS class present this abstract data
        type this way. All presentations either show a simple pseudocode
        implementation, or appeal to a mental model derived from a real life
        experience, which is still a kind of simple pseudocode implementation,
        except it is in real life terms instead of CS terms.

        Comment

        • Alex Martelli

          Re: Express What, not How.

          Rainer Deyke wrote:
          ...[color=blue]
          > (x == 0).if_true(anon ymous_code_bloc k)
          >
          > Sure, Python already has an 'if' statement. That does not mean that there
          > are no other control structures worth implementing as HOFs.[/color]

          True: if we had good code block literals, they'd help. However, the
          issue of having to name the code block (with a def) is perhaps not as
          crucial as it appears -- as important (and not implicit in the code
          block being a literal) is in what scope the code block gets and sets
          variables. If an anonymous code block, like a lambda, is totally
          equivalent to a named function (sets variable locally, gets them in
          lexical scope), then being able to write the above rather than

          def guarded(): anonymous_code_ block
          (x == 0).if_true(guar ded)

          is a somewhat minor. The problem is, what could I possibly write in the
          code block in order to obtain the same effect as with:
          if x == 0:
          x = 23
          y += 1
          and that's an issue of scope, not one of naming or not naming the block.
          (Mertz's proposal for a 'block' keyword addresses this, but by wanting
          the block's scope to be that of the caller rather than that of the
          definer, it of course solves none of the problems Smalltalks block solve).

          [color=blue]
          > However, I think I can make an even stronger case for anonymous functions
          > from my own code, which is littered with lambda expressions such as
          > 'lambda:
          > 1', 'lambda: 0', and 'lambda: None'. Giving those mini functions
          > individual names would be an atrocity, and even a factory function that
          > returns these mini functions would only hurt readability.[/color]

          I disagree: I find nullary(1), nullary(0) and the like very readable.
          "lambda: x" is IMHO much more of a problem -- again because of scope.


          Alex

          Comment

          • Albert Lai

            Re: Express What, not How.

            Albert Lai <trebla@vex.net > writes:
            [color=blue]
            > Hung : LiDui
            > MoYun : LiDui -> Bool
            > PaiDui: (LiDui,Object) -> LiDui
            > DuiTau: LiDui -> Object
            > LeiDui: LiDui -> LiDui
            >
            > MoYun(Hung) is true.
            > For any LiDui d:
            > If MoYun(d) is true, we have LeiDui(PaiDui(d ,o))=d and DuiTau(PaiDui(d ,o))=o.
            > If MoYun(d) is false, we have LeiDui(PaiDui(d ,o))=PaiDui(Lei Dui(d),o).
            >
            > That's it.[/color]

            I knew I forgot something.

            If MoYun(d) is false, we have LeiDui(PaiDui(d ,o))=PaiDui(Lei Dui(d),o)
            and DuiTau(PaiDui(d ,o))=DuiTau(d).

            MoYun(PaiDui(d, o)) is false.

            Comment

            • David Eppstein

              Re: Express What, not How.

              In article <4u65ir2eya.fsf @vex.net>, Albert Lai <trebla@vex.net > wrote:
              [color=blue]
              > It is a functional (immutable) abstract data type, so most operations
              > take an existing instance as a parameter and return a new instance.
              > The name of the abstract data type is LiDui.
              >
              > Hung : LiDui
              > MoYun : LiDui -> Bool
              > PaiDui: (LiDui,Object) -> LiDui
              > DuiTau: LiDui -> Object
              > LeiDui: LiDui -> LiDui
              >
              > MoYun(Hung) is true.
              > For any LiDui d:
              > If MoYun(d) is true, we have LeiDui(PaiDui(d ,o))=d and
              > DuiTau(PaiDui(d ,o))=o.
              > If MoYun(d) is false, we have LeiDui(PaiDui(d ,o))=PaiDui(Lei Dui(d),o).
              >
              > That's it.[/color]

              You sure you don't need a little more? This seems to fit both stacks
              (MoYun always = True) and queues (MoYun true only for Hung).

              That's one trouble with axiomatic definitions -- it's hard to be sure
              you've expressed all of the behavior you intend to specify.
              Another is that they can be difficult to understand.

              --
              David Eppstein http://www.ics.uci.edu/~eppstein/
              Univ. of California, Irvine, School of Information & Computer Science

              Comment

              • james anderson

                Re: Express What, not How.



                Adrian Hey wrote:[color=blue]
                >
                > james anderson wrote:
                >[color=green]
                > > Marcin 'Qrczak' Kowalczyk wrote:[color=darkred]
                > >> Most high level languages have anonymous functions for a reason.
                > >>[/color]
                > >
                > > i'm just wondering if you're serious about all of this.[/color]
                >
                > I think Marcin is serious, and any Haskeller would agree I suspect.
                >[/color]

                i have no argument with the utility of lambda abstractions.
                i am trying only to understand the implications of an argument which, at least
                as stated, rather unequivocally deprecates bindings.
                the position which was proposed in the forgoing post was rather extreme.
                i enquired to see of m.kowalczyk might offer some practical examples from
                which it might be possible to learn something.
                [color=blue]
                > A good example from Haskell would be the use of lambda abstractions
                > as the second argument of the monadic >>= operator. Supplying names
                > for all those abstractions would be really awkward and yield highly
                > unreadable code IMO.[/color]

                yes, i am good friends with lambda abstractions. we get along well and respect
                each other. i am, however, neither married to one, nor an initiate in a sect
                which deems it a transgression to utter the name of another deity.

                ....

                Comment

                • Jacek Generowicz

                  Re: Python syntax in Lisp and Scheme

                  Paul Rubin <http://phr.cx@NOSPAM.i nvalid> writes:
                  [color=blue]
                  > Jacek Generowicz <jacek.generowi cz@cern.ch> writes:[color=green]
                  > > However, please _do_ tell me if you hear of anyone implementing Python
                  > > in Lisp[*].
                  > >
                  > > Having Python as a front-end to Lisp[*] (as it is now a front-end to
                  > > C, C++ and Java) would be very interesting indeed.[/color]
                  >
                  > That would not be simple to do, because of weird Python semantics.[/color]

                  Could you elaborate on how Python semantics are weird (any more weird
                  than, say, Common Lisp)? and on why making a Common Lisp
                  implementation of Python would be any less simple than making a C
                  or Java implementation of Python?
                  [color=blue]
                  > But doing a Python dialect (a little bit different from CPython) would
                  > be worthwhile.[/color]

                  In what sense would it differ? (I would not insist that it conform to
                  the Python/C API :-)

                  Would it differ from CPython any more than Jython differs from
                  CPython?

                  Comment

                  • Lulu of the Lotus-Eaters

                    Re: Express What, not How.

                    "Rainer Deyke" <rainerd@eldwoo d.com> wrote previously:
                    |However, I think I can make an even stronger case for anonymous functions
                    |from my own code, which is littered with lambda expressions such as 'lambda:
                    |1', 'lambda: 0', and 'lambda: None'. Giving those mini functions individual
                    |names would be an atrocity

                    Let's say I created a module lambdas.py (and generalized your functions):

                    OneFunc = lambda *a,**kw: 1
                    ZeroFunc = lambda *a,**kw: 0
                    NoneFunc = lambda *a,**kw: None
                    ...etc...

                    In my application, I might have:

                    from lambdas import *
                    ...
                    widget(param1, param2, callback=isCond and myFunc or NoneFunc)

                    Where exactly does the atrocity arise?! If anything, it's slightly more
                    readable than Deyke's little lambdas (and a little more concise too).

                    Yours, Lulu...

                    --
                    Keeping medicines from the bloodstreams of the sick; food from the bellies
                    of the hungry; books from the hands of the uneducated; technology from the
                    underdeveloped; and putting advocates of freedom in prisons. Intellectual
                    property is to the 21st century what the slave trade was to the 16th.


                    Comment

                    • prunesquallor@comcast.net

                      Re: Python syntax in Lisp and Scheme

                      "Terry Reedy" <tjreedy@udel.e du> writes:
                      [color=blue]
                      > "Pascal Bourguignon" <spam@thalassa. informatimago.c om> wrote in
                      > message news:87ekxfmhhl .fsf@thalassa.i nformatimago.co m...[color=green]
                      >>
                      >> prunesquallor@c omcast.net writes:[color=darkred]
                      >> > Since having the correct amount of whitespace is *vital* to the
                      >> > correct operation of a Python program, it seems that the task of
                      >> > maintaining it is made that much more difficult because it is only
                      >> > conspicuous by its absence.[/color][/color]
                      >[color=green]
                      >> That remembers me that when the languages had significant spaces,[/color]
                      > the[color=green]
                      >> programming was done with forms, sheets of physical paper[/color]
                      > preprinted[color=green]
                      >> with empty spaces:[/color]
                      > [further idiocy snipped]
                      >
                      > I do believe that several Lispers have suggested that people should
                      > give Lisp a fair trial before rejecting it on account of parentheses
                      > or macros. The same goes, of course, for Python and significant
                      > indents/dedents. For most people who try Python, freedom from
                      > visually redundant fences is a feature. Those who find it a bother
                      > after trying are welcome to chose another language.
                      >
                      > What makes the comments above doubly absurd is that Lisp has as much
                      > or more need for 'significant spaces' as Python.[/color]

                      That is simply incorrect. It is a small matter to set the readtable
                      such that things like (+x3) are interpreted as (+ x 3). This would
                      make it much more difficult to use complicated variable names, but
                      that's the tradeoff.
                      [color=blue]
                      > Compare (1,2,3) versus (1 2 3). Having the "correct amount of
                      > whitespace is *vital* to the correct operation of a" Lisp program as
                      > much as for any other. Do Lispers therefore use forms? I suspect
                      > not ;-)[/color]

                      There's a bit of a difference between the whitespace separating tokens
                      and the whitespace that delineates blocks. The former is a member
                      of the half-open interval (0, +inf), the latter is a singleton.

                      Comment

                      • Donald 'Paddy' McCarthy

                        Re: Code block literals



                        John Roth wrote:[color=blue]
                        > "Greg Ewing (using news.cis.dfn.de )" <g2h5dqi002@sne akemail.com> wrote in
                        > message news:bmd3cv$lk5 1t$1@ID-169208.news.uni-berlin.de...
                        >[color=green]
                        >>Dave Benjamin wrote:
                        >>[color=darkred]
                        >>>In that case, why do we eschew code blocks, yet have no problem with the
                        >>>implicit invocation of an iterator,[/color]
                        >>
                        >>I don't think code blocks per se are regarded as a bad thing.
                        >>The problem is that so far nobody has come up with an entirely
                        >>satisfactor y way of fitting them into the Python syntax as
                        >>expressions .[/color]
                        >
                        >
                        > I know. I played around with the idea a bit after it came up a couple
                        > of weeks ago, and identified a number of issues.
                        >[/color]
                        <<SNIP>>[color=blue]
                        >
                        > So let's say I want to use a code block instead of
                        > a lambda or a named function in a map:
                        >
                        > foobar = map(def (x, y, z):
                        > astatement
                        > anotherstatemen t
                        > list1, list2, list3)
                        >[/color]
                        <<SNIP>>[color=blue]
                        > A third item is that I don't really care if we use 'def'
                        > or not. Borrowing the vertical bar from Ruby, the map
                        > example becomes:
                        >
                        > foobar = map(| x, y, z |
                        > astatement
                        > anotherstatemen t
                        > list1, list2, list3)
                        >
                        > I kind of like this better, except for one really unfortunate
                        > issue: it's going to raise havoc with code coloring algorithms
                        > for a while.
                        >
                        > John Roth
                        >[/color]

                        Hmm,
                        How about just using the presence of (...):: as starting a code block?
                        A call to a function that might take two function args and something else:
                        foo = bar(func1, func2, nonfunc)
                        would become:
                        foo = bar( (a,b)::
                        astatement
                        somemorestateme nts
                        ,(c,d,e)::
                        anotherstatemen t
                        yetmorestatemen ts
                        ,nonfunc)

                        I used the double colon after the closing bracket as the statements of
                        the enclosed statement block must be double indented w.r.t foo

                        I guess the indentation of the arguments of bar (not including the
                        statement blocks could have less restrictive indentation.
                        Just as you could write
                        foo = bar(
                        func1,
                        func2,
                        nonfunc)
                        the indentation rules would have to be that the statement block is
                        double indented on the line after ):: and the statement block ends on
                        the next line with LESS indentation (more indentation would be tart of
                        the statement block).

                        Pad.


                        Comment

                        • Marcin 'Qrczak' Kowalczyk

                          Re: Express What, not How.

                          On Wed, 15 Oct 2003 00:41:28 +0000, Raffael Cavallaro wrote:
                          [color=blue]
                          > Your argument is based on the assumption that whenever people express
                          > _what_ a function does, they do so badly, with an inappropriate name.[/color]

                          Sometimes there is no name which is more clear than the definition.

                          A random example from OCaml source:
                          if List.exists (fun q -> q.pat_loc = p.pat_loc) ps2 then ...

                          Would you write it like this? Please fill the appropriate <name>:
                          let <name> q = q.pat_loc = p.pat_loc in
                          if List.exists <name> ps2 then ...

                          Note that the function must be written here because it uses p which is
                          local, unless p was moved to its parameters and partially applied here
                          (this technique works for OCaml because of curring, it won't work for Lisp
                          or Scheme).
                          [color=blue][color=green]
                          >> The code also gets longer[/color]
                          >
                          > No, it gets shorter, because you don't repeat your use of the same
                          > abstraction over and over.[/color]

                          If it's used only once then the code is longer - see above.
                          [color=blue][color=green]
                          >> When you have lots of short functions, it's harder to find them. There
                          >> are many names to invent for the writer and many names to rememner for
                          >> a reader.[/color]
                          >
                          > Which is why names should be descriptive.[/color]

                          Great, many long names :-)
                          [color=blue][color=green]
                          >> Why do you insist on naming *functions*? You could equally well say
                          >> that every list should be named, so you would see its purpose rather
                          >> than its contents.[/color]
                          >
                          > I think this concept is called variable bindings ;^)[/color]

                          I don't say I don't use variables. I say I don't use variables for *every*
                          subexpression. And sure I do use named functions, but not every function
                          deserves to be named.
                          [color=blue]
                          > In the Smalltalk community the rule of thumb is that if a method body
                          > gets to be more than a few lines, you've failed to break it down into
                          > smaller abstractions (i.e., methods).[/color]

                          Hmm, Smalltalk blocks are anonymous functions. Do you reject Smalltalk
                          blocks too? :-)
                          [color=blue]
                          > Yes, but they should live inside the bodies of named functions. Not lie
                          > exposed in the middle of higher level abstractions. Please also see my
                          > reply to Joe Marshall/Prunesquallor a few posts up in this thread.[/color]

                          You contradict yourself. First you say that "any anonymous function syntax
                          is undesirable", and they you accept anonymous functions in the middle of
                          higher level abstractions.

                          --
                          __("< Marcin Kowalczyk
                          \__/ qrczak@knm.org. pl
                          ^^ http://qrnik.knm.org.pl/~qrczak/

                          Comment

                          • james anderson

                            Re: Express What, not How.



                            "Brian McNamara!" wrote:[color=blue]
                            >
                            > Raffael Cavallaro <raffaelcavalla ro@junk.mail.me .not.mac.com> once said:[color=green]
                            > > Marcin 'Qrczak' Kowalczyk <qrczak@knm.org .pl> wrote:[color=darkred]
                            > >> Sometimes a function is so simple that its body is more clear than any
                            > >> name. A name is an extra level of indirection. You must follow it to be
                            > >> 100% sure what the function means, or to understand what does it really
                            > >> mean that it does what it's named after.[/color]
                            > >
                            > >Your argument is based on the assumption that whenever people express
                            > >_what_ a function does, they do so badly, with an inappropriate name.[/color]
                            > ...
                            >
                            > If I understand you correctly, you would insist I write something like
                            >
                            > nat :: Parser Int
                            > nat = do {c <- digit; return charToInt c}
                            > `chainl1` combineDigits
                            > where combineDigits = return \x y -> 10*x+y[/color]

                            when i read r.cavallaro's note, i saw no proscriptions. upon rereading it i
                            observe a value judgement and several characterizatio ns. perhaps the reader
                            somehow misinterpreted them as pre/proscriptions. pehaps if the term "force"
                            were replaced with "require" the b.mcnamara would agree that there is no
                            contraction between them and his post in reply.

                            ....[color=blue]
                            >
                            > By only naming the most reusable abstractions (and, ideally, selecting
                            > a set which are mostly orthogonal to one another), we provide a "core
                            > vocabulary" which captures the essential basis of the domain. Lambda
                            > then takes us the rest of the way. In my opinion, a core vocabulary of
                            > named functions plus lambda is better than a separate name for every
                            > abstraction. In natural language, such a scheme would be considered
                            > double-plus-un-good, but in programming, I think it lends itself to the
                            > simplest and most precise specifications.[/color]

                            what is the utility in overstating cavallaro's argument, in order to set up a
                            straw argument which reaches a conclusion quite in keeping with the original?
                            perhaps, yes ther is some utility in reiterating that extreme
                            pre/proscriptions in either direction are counterproducti ve. but, that in no
                            way weakens his argument.
                            [color=blue]
                            >
                            > I agree with your one of your overall theses, which is that we should
                            > focus on the "what" rather than the "how". Where our opinions diverge,
                            > however, is that I think sometimes the best way to communicate an
                            > abstraction is to show the "how" inline, rather than creating a new
                            > name in an attempt to capture the "what".
                            >[/color]

                            Comment

                            • Vijay L

                              Re: Express What, not How.

                              gt5163b@prism.g atech.edu (Brian McNamara!) wrote in message news:<bmicpp$if k$1@news-int2.gatech.edu >...[color=blue]
                              >
                              > I am in total agreement with Marcin. What you (Raffael) say here
                              > sounds simply like dogma, rather than practical advice for constructing
                              > software.
                              >
                              > As a short practical example of what I'm saying, consider code like[/color]

                              [snip]
                              [color=blue]
                              > If I understand you correctly,[/color]

                              It appears you don't.

                              [snip]
                              [color=blue]
                              >
                              > In my opinion, the code here is worse than the original.[/color]

                              I agree.

                              [big snip]

                              You're taking things to a huge extreme to prove your point. Obviously
                              Raffael, being a programmer himself isn't suggesting that each and
                              every calculation/operation be put in a named function. The best
                              benchmark, is, I guess, the programmer himself. When programming, if
                              you find some portion of code that /you/ feel won't be understand when
                              you're rereading it or, you took a chunk out of a function to debug it
                              and at that point had to give it a name as another function etc etc;
                              /then/ keep that portion aside as a named function. It reduces the
                              burden on the person reading the original function that has been
                              shortened and, _gives him the choice_ to read this other function that
                              has been abstracted in that code.

                              Cheers,
                              Vijay

                              All future commitments are optimistic.

                              Comment

                              • Edi Weitz

                                Re: Python syntax in Lisp and Scheme

                                On Thu, 16 Oct 2003 11:43:06 -0700, David Eppstein <eppstein@ics.u ci.edu> wrote:
                                [color=blue]
                                > For simple use of built-in libraries,
                                > http://online.effbot.org/2003_08_01_archive.htm#troll
                                > looks like a good test case.[/color]

                                Quick hack follows.

                                edi@bird:/tmp > cat troll.lisp
                                (asdf:oos 'asdf:load-op :aserve)
                                (asdf:oos 'asdf:load-op :cl-ppcre)

                                (defparameter *scanner*
                                (cl-ppcre:create-scanner
                                "<a href=\"AuthorTh reads.asp[^\"]*\">([^<]+)</a></td>\\s*
                                <td align=\"center\ ">[^<]+</td>\\s*
                                <td align=\"center\ ">[^<]+</td>\\s*
                                <td align=\"center\ ">\\d+</td>\\s*
                                <td align=\"center\ ">(\\d+)</td>\\s*
                                <td align=\"center\ ">(\\d+)</td>\\s*
                                <td align=\"center\ ">\\d+</td>\\s*
                                <td align=\"center\ ">(\\d+)</td>\\s*"))

                                (defun troll-checker (name)
                                (let ((target
                                (net.aserve.cli ent:do-http-request
                                (format nil "http://netscan.researc h.microsoft.com/Static/author/authorprofile.a sp?searchfor=~A " name)
                                :protocol :http/1.0)))
                                (cl-ppcre:do-scans (match-start match-end reg-starts reg-ends *scanner* target)
                                (flet ((nth-group (n)
                                (subseq target (aref reg-starts n) (aref reg-ends n))))
                                (let* ((group (nth-group 0))
                                (posts (parse-integer (nth-group 1)))
                                (replies (parse-integer (nth-group 2)))
                                (threads-touched (parse-integer (nth-group 3)))
                                (reply-to-post-ratio (/ replies posts))
                                (threads-to-post-ratio (/ threads-touched posts)))
                                (unless (< posts 10)
                                (format t "~55A R~,2F T~,2F ~:[~;TROLL~:[?~;!~]~]~%"
                                (subseq group 0 (min 55 (length group)))
                                reply-to-post-ratio
                                threads-to-post-ratio
                                (and (> reply-to-post-ratio .8)
                                (< threads-to-post-ratio .4))
                                (< threads-to-post-ratio .2))))))))

                                (compile 'troll-checker)

                                edi@bird:/tmp > cmucl
                                ; Loading #p"/home/edi/.cmucl-init".
                                CMU Common Lisp 18e, running on bird.agharta.de
                                With core: /usr/local/lib/cmucl/lib/lisp.core
                                Dumped on: Thu, 2003-04-03 15:47:12+02:00 on orion
                                Send questions and bug reports to your local CMUCL maintainer,
                                or see <http://www.cons.org/cmucl/support.html>.
                                Loaded subsystems:
                                Python 1.1, target Intel x86
                                CLOS 18e (based on PCL September 16 92 PCL (f))
                                * (load "troll")

                                ; loading system definition from /usr/local/lisp/Registry/aserve.asd into
                                ; #<The ASDF1017 package, 0/9 internal, 0/9 external>
                                ; registering #<SYSTEM ASERVE {4854AEF5}> as ASERVE
                                ; loading system definition from /usr/local/lisp/Registry/acl-compat.asd into
                                ; #<The ASDF1059 package, 0/9 internal, 0/9 external>
                                ; registering #<SYSTEM ACL-COMPAT {4869AD35}> as ACL-COMPAT
                                ; loading system definition from /usr/local/lisp/Registry/htmlgen.asd into
                                ; #<The ASDF1145 package, 0/9 internal, 0/9 external>
                                ; registering #<SYSTEM HTMLGEN {487E64C5}> as HTMLGEN
                                ; loading system definition from /usr/local/lisp/Registry/cl-ppcre.asd into
                                ; #<The ASDF1813 package, 0/9 internal, 0/9 external>
                                ; registering #<SYSTEM #:CL-PPCRE {48F32835}> as CL-PPCRE
                                ; Compiling LAMBDA (NAME):
                                ; Compiling Top-Level Form:
                                T
                                * (troll-checker "edi@agharta.de ")
                                comp.lang.lisp R0.93 T0.63
                                NIL
                                * (troll-checker "eppstein@ics.u ci.edu")
                                rec.photo.digit al R1.00 T0.76
                                rec.arts.sf.wri tten R0.99 T0.57
                                comp.lang.pytho n R0.98 T0.64
                                rec.photo.equip ment.35mm R1.00 T0.73
                                sci.math R1.00 T0.77
                                rec.puzzles R1.00 T0.75
                                comp.theory R1.00 T0.56
                                comp.graphics.a lgorithms R1.00 T0.87
                                comp.sys.mac.ap ps R1.00 T0.69
                                NIL
                                * (troll-checker "spam@thalassa. informatimago.c om")
                                comp.lang.lisp R0.91 T0.44
                                fr.comp.os.unix R1.00 T0.70
                                es.comp.os.linu x.programacion R1.00 T0.67
                                fr.comp.lang.li sp R1.00 T0.40 TROLL?
                                comp.unix.progr ammer R1.00 T0.92
                                sci.space.moder ated R1.00 T0.43
                                gnu.emacs.help R0.95 T0.84
                                sci.space.polic y R1.00 T0.33 TROLL?
                                alt.folklore.co mputers R1.00 T0.43
                                comp.lang.schem e R0.83 T0.58
                                fr.comp.os.mac-os.x R0.92 T0.83
                                NIL

                                Granted, Portable AllegroServe[1] and CL-PPCRE[2] aren't "built-in"
                                (but freely available, compatible with various CL compilers, and easy
                                to install) and Python might have a bit more syntactic sugar but it
                                wasn't _too_ hard to do that in Lisp.

                                Edi

                                [1] <http://portableaserve. sf.net/>
                                [2] <http://weitz.de/cl-ppcre/>

                                Comment

                                Working...