Python syntax in Lisp and Scheme

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Pascal Bourguignon

    Re: Python syntax in Lisp and Scheme

    gregm@cs.uwa.ed u.au writes:[color=blue]
    > What does it mean to take a variable-name as an argument? How is that
    > different to taking a pointer? What does it mean to take "code" as an
    > argument? Is that different to taking a function as an argument?[/color]

    The difference is that you can declare (compilation-time) it and
    associated variables or functions.

    For example, I recently defined this macro, to declare at the same
    time a class and a structure, and to define a couple of methods to
    copy the objects to and from structures.

    That's so useful that even cpp provide us with a ## operator to build
    new symbols.

    (DEFMACRO DEFCLASS-AND-STRUCT (NAME SUPER-CLASSES ATTRIBUTES OPTIONS)
    (LET ((STRUCT-NAME (INTERN (FORMAT NIL "~A-STRUCT" NAME))))
    `(PROG1
    (DEFCLASS ,NAME ,SUPER-CLASSES ,ATTRIBUTES ,OPTIONS)
    (DEFSTRUCT ,STRUCT-NAME
    ,@(MAPCAR (LAMBDA (ATTRIBUTE)
    (CONS
    (CAR ATTRIBUTE)
    (CONS (GETF (CDR ATTRIBUTE) :INITFORM NIL)
    (IF (GETF (CDR ATTRIBUTE) :TYPE NIL)
    NIL
    (LIST :TYPE (GETF (CDR ATTRIBUTE) :TYPE))))))
    ATTRIBUTES))
    (DEFMETHOD COPY-TO-STRUCT ((SELF ,NAME))
    (MAKE-STRUCT
    ',NAME
    ,@(MAPCAN (LAMBDA (ATTRIBUTE)
    `(,(INTERN (STRING (CAR ATTRIBUTE)) "KEYWORD")
    (COPY-TO-STRUCT (SLOT-VALUE SELF ',(CAR ATTRIBUTE)))))
    ATTRIBUTES)))
    (DEFMETHOD COPY-FROM-STRUCT ((SELF ,NAME) (STRUCT ,STRUCT-NAME))
    ,@(MAPCAR
    (LAMBDA (ATTRIBUTE)
    `(SETF (SLOT-VALUE SELF ',(CAR ATTRIBUTE))
    (,(INTERN (FORMAT NIL "~A-~A"
    STRUCT-NAME (CAR ATTRIBUTE))) STRUCT)))
    ATTRIBUTES)
    SELF)
    ))
    );;DEFCLASS-AND-STRUCT


    --
    __Pascal_Bourgu ignon__

    Do not adjust your mind, there is a fault in reality.

    Comment

    • Raymond Wiker

      Re: Python syntax in Lisp and Scheme

      Matthias <no@spam.pls> writes:
      [color=blue]
      > 1.) Inventing new control structures (implement lazy data structures,
      > implement declarative control structures, etc.)
      > => This one is rarely needed in everyday application programming and
      > can easily be misused.[/color]

      This is, IMHO, wrong. One particular example is creating
      macros (or read macros) for giving values to application-specific data
      structures.
      [color=blue]
      > You have to know if you want a sharp knife (which may hurt you when
      > misused) or a less sharper one (where it takes more effort to cut
      > with).[/color]

      It is easier to hurt yourself with a blunt knife than a sharp
      one.

      --
      Raymond Wiker Mail: Raymond.Wiker@f ast.no
      Senior Software Engineer Web: http://www.fast.no/
      Fast Search & Transfer ASA Phone: +47 23 01 11 60
      P.O. Box 1677 Vika Fax: +47 35 54 87 99
      NO-0120 Oslo, NORWAY Mob: +47 48 01 11 60

      Try FAST Search: http://alltheweb.com/

      Comment

      • Bengt Richter

        Re: Python syntax in Lisp and Scheme

        On Mon, 6 Oct 2003 11:39:55 +0200, Gerrit Holl <gerrit@nl.linu x.org> wrote:
        [color=blue]
        >Ingvar Mattsson wrote:[color=green]
        >> It's actually even worse than you think. Imagine you want "blank
        >> lines" in your code, so act as paragraph separators. Do these require
        >> indentation, even though there is no code on them? If so, how does
        >> that interact with a listener? From what I can tell, the option chosen
        >> in the Python (the language) community, the listener and the file
        >> reader have different view on blank lines. This makes it harder than
        >> necessary to edit stuff in one window and "just paste" code from
        >> another. Bit of a shame, really.[/color]
        >[/color]
        I think I agree somewhat. The problem is detecting end-of-chunk from the user input.
        I think it would be possible to write a different listener that would accept
        chunks terminated with an EOF from the user using some key binding, like a function key
        or Ctl-z or Ctl-d. Then you could type away until you wanted it interpreted.
        A zero length chunk followed by EOF would terminate the overall listener.

        The source is open if you want to try it ;-) Let us know how it feels to use.
        Alternatively, maybe interactively postponing blank-line dedent processing until the
        next line would be better. Two blank lines at the end of an indented series of chuncks
        separated by a single blank line would be fairly natural. If there was no indent legal
        on the next line, you'd process immediately, not go to ... prompt. But this is tricky
        to get right.
        [color=blue]
        >Blank lines are ignored by Python.
        >[/color]
        You are right re the language, but the interactive command line interface (listener)
        doesn't ignore them. (Its syntactical requirements are a somewhat separate issue from
        Python the language, but they are part of the overall Python user experience):
        [color=blue][color=green][color=darkred]
        >>> def foo(): print 'foo'[/color][/color][/color]
        ...[color=blue][color=green][color=darkred]
        >>> foo()[/color][/color][/color]
        foo[color=blue][color=green][color=darkred]
        >>> if 1:[/color][/color][/color]
        ... def foo(): print 'foo'
        ... foo()
        ...
        foo

        Regards,
        Bengt Richter

        Comment

        • David Rush

          Re: Python syntax in Lisp and Scheme

          On Sat, 04 Oct 2003 16:48:00 GMT, <prunesquallor@ comcast.net> wrote:[color=blue]
          > I agree that injudicious use of macros can destroy the readability of
          > code, but judicious use can greatly increase the readability. So
          > while it is probably a bad idea to write COND1 that assumes
          > alternating test and consequence forms, it is also a bad idea to
          > replicate boilerplate code because you are eschewing macros.[/color]

          But it may also be a mistake to use macros for the boilerplate code when
          what you really need is a higher-order function...

          david rush
          --
          (\x.(x x) \x.(x x)) -> (s i i (s i i))
          -- aki helin (on comp.lang.schem e)

          Comment

          • David Rush

            Re: Python syntax in Lisp and Scheme

            On Sun, 5 Oct 2003 11:55:00 -0400, Terry Reedy <tjreedy@udel.e du> wrote:[color=blue]
            > "Shriram Krishnamurthi" <sk@cs.brown.ed u> wrote in message[color=green]
            >> "Terry Reedy" <tjreedy@udel.e du> writes:[color=darkred]
            >>> Lisp (and possibly other languages I am not familiar with) adds the
            >>> alternative of *not* evaluating arguments but instead passing them
            >>> as unevaluated expressions.[/color][/color]
            >[color=green]
            >> I'm sorry -- you appear to be hopelessly confused on this point.[/color]
            >
            > Actually, I think I have just achieved clarity: the one S-expression
            > syntax is used for at least different evaluation protocols -- normal
            > functions and special forms, which Lispers have also called FSUBR and
            > FEXPR *functions*.[/color]

            Well, I got it, and you raised a good point but used the wrong terminology.
            To know how any particular sexp is going to be evaluated you must know
            whether the head symbol is bound to either a macro or some other
            (preferably
            a function) value. The big difference between the CL and Scheme communities
            in this respect is that Scheme requires far fewer macros because it has
            first-class functions (no need for the context-sensitive funcall). So while
            you have a valid point, and indeed a good reason for minimizing the number
            of macros in a program, in practice this is *much* less of a problem in
            Scheme.
            [color=blue][color=green]
            >> There are no functions in Scheme whose arguments are not evaluated.[/color]
            >
            > That depends on who defines 'function'.[/color]

            In Scheme (and Lisp generally I suspect) function != macro for any values
            of the above. Both are represented as s-expression 'forms' (which is the
            correct local terminology)
            [color=blue]
            > "If anything I write below about Lisp does not apply to Scheme
            > specificly, my aplogies in advance."[/color]

            No bother...

            david rush
            --
            (\x.(x x) \x.(x x)) -> (s i i (s i i))
            -- aki helin (on comp.lang.schem e)

            Comment

            • Joe Marshall

              Re: Python syntax in Lisp and Scheme

              David Rush <drush@aol.ne t> writes:
              [color=blue]
              > On Sat, 04 Oct 2003 16:48:00 GMT, <prunesquallor@ comcast.net> wrote:[color=green]
              >> I agree that injudicious use of macros can destroy the readability of
              >> code, but judicious use can greatly increase the readability. So
              >> while it is probably a bad idea to write COND1 that assumes
              >> alternating test and consequence forms, it is also a bad idea to
              >> replicate boilerplate code because you are eschewing macros.[/color]
              >
              > But it may also be a mistake to use macros for the boilerplate code when
              > what you really need is a higher-order function...[/color]

              Certainly.

              One should be willing to use the appropriate tools: higher-order
              functions, syntactic abstraction, and meta-linguistic abstraction
              (embedding a domain-specific `tiny language' within the host
              language). Macros come in handy for the latter two.

              Comment

              • Neelakantan Krishnaswami

                Re: Python syntax in Lisp and Scheme

                In article <blr1cq$bb1$1@e nyo.uwa.edu.au> , gregm@cs.uwa.ed u.au wrote:[color=blue]
                > In comp.lang.funct ional Erann Gat <my-first-name.my-last-name@jpl.nasa.g ov>
                > wrote:
                >:> I can't see why a LISP programmer would even want to write a macro.
                >: That's because you are approaching this with a fundamentally flawed
                >: assumption. Macros are mainly not used to make the syntax prettier
                >: (though they can be used for that). They are mainly used to add features
                >: to the language that cannot be added as functions.
                >
                > Really? Turing-completeness and all that... I presume you mean
                > "cannot so easily be added as functions", but even that would
                > surprise me. (Unless you mean cannot be added _to_Lisp_ as
                > functions, because I don't know as much as I'd like to about Lisp's
                > capabilities and limitations.)[/color]

                You know Haskell. Think about the do-noatation for monads: it takes
                what would be awkward, error-prone code (using >> and >>= manually)
                and makes it pleasant and readable. Do-notation is basically a macro
                (and can easily be expressed as such in Scheme or Lisp). Syntactic
                convenience is very important; consider how many fewer programmers in
                ML are willing to reach for a monadic solution, even when it would be
                appropriate. Or for that matter, think how many fewer Java programmers
                are willing to write a fold than in ML or Haskell, even when it would
                be appropriate.


                --
                Neel Krishnaswami
                neelk@cs.cmu.ed u

                Comment

                • Matthew Danish

                  Re: Python syntax in Lisp and Scheme (macro tangent)

                  On Mon, Oct 06, 2003 at 10:19:46AM +0000, gregm@cs.uwa.ed u.au wrote:[color=blue]
                  > In comp.lang.funct ional Marco Baringer <mb@bese.it> wrote:
                  > : gregm@cs.uwa.ed u.au writes:
                  > :> Really? Turing-completeness and all that... I presume you mean "cannot
                  > :> so easily be added as functions", but even that would surprise me.
                  >
                  > : well you can pass around code full of lambdas so most macros (expect
                  > : the ones which perform hairy source transformations ) can be rewritten
                  > : as functions, but that isn't the point. Macros are about saying what
                  > : you mean in terms that makes sense for your particular app.
                  >
                  > OK, so in some other application, they might allow you to extend the
                  > syntax of the language to encode some problem domain more naturally?[/color]

                  Right.
                  [color=blue]
                  >
                  > :> OK, that's _definitely_ just a filter:
                  > : no it's not, and the proof is that it wasn't written as a filter.
                  >
                  > He was saying that this could not be done in Python, but Python has
                  > a filter function, AFAIK.[/color]

                  He meant the way it was expressed. Java can ``do'' it too, but it's not
                  going to look as simple.
                  [color=blue]
                  >
                  > : For whatever reason the author of that snippet decided that the code
                  > : should be written with WITH-COLLECTOR and not as a filter, some
                  > : languages give you this option, some don't, some people think this is
                  > : a good thing, some don't.
                  >
                  > Naturally. I'm against extra language features unless they increase
                  > the expressive power, but others care more for ease-of-writing and
                  > less for ease-of-reading and -maintaining than I do.[/color]

                  Then you should like macros, because ease-of-reading and -maintaining is
                  precisely why I use them. Like with functions, being able to label
                  common abstractions is a great maintainability boost.

                  You don't write ((lambda (x) ...) 1) instead of (let ((x 1)) ...), right?
                  [color=blue]
                  > :> : DO-FILE-LINES and WITH-COLLECTOR are macros, and they can't be implemented
                  > :> : any other way because they take variable names and code as arguments.
                  > :> What does it mean to take a variable-name as an argument? How is that
                  > :> different to taking a pointer? What does it mean to take "code" as an
                  > :> argument? Is that different to taking a function as an argument?
                  > : You are confusing the times at which things happen. A macro is
                  > : expanded at compile time,
                  >
                  > OK, yep. It should have occurred to me that that was the difference.
                  > So now the question is "what does that give you that higher-order
                  > functions don't?".
                  > : Another trivial example:
                  > : <IF-BIND>
                  >
                  > : Macros allow me to say what I _mean_, not what the compiler wants.
                  >
                  > Interesting. It would be interesting to see an example where it allows
                  > you to write the code in a less convoluted way, rather than the three
                  > obfuscating (or would the non-macro Lisp versions be just as obfuscated?
                  > I know Lisp is fine for higher-order functions, but I guess the IF-BIND
                  > stuff might be hard without pattern-matching.) examples I've seen so far.[/color]

                  Here's an example that I am currently using:

                  (definstruction move ((s register) (d register))
                  :sources (s)
                  :destinations (d)
                  :template "movl `s0, `d0"
                  :class-name move-instruction)

                  1. This expands into a
                  (defmethod make-instruction-move ((s register) (d register)) ...)
                  which itself is called indirectly, but most importantly it allows the
                  compiler to compile a multiple-dispatch method statically rather than
                  trying to replicate that functionality at runtime (which would require
                  parsing a list of parameters supplied by the &rest lambda-list keyword,
                  not to mention implementing multiple-dispatch).

                  2. Sources and destinations can talk about variable names rather than indices
                  into a sequence. (Templates cannot because they need the extra layer of
                  indirection--the source and destination lists are subject to change in
                  this system currently. Well, I suppose it could be worked out anyway,
                  perhaps if I have time I will try it).

                  3. Originally I processed the templates at run-time, and upon profiling
                  discovered that it was the most time-consuming function by far. I modified
                  the macro to process the template strings statically and produce a
                  function which could be compiled with the rest of the code, and the
                  overhead completely disappeared. I can imagine a way to do this with
                  functions: collect a list of functions which take the relevant values
                  as arguments, then map over them and apply the results to format.
                  This is less efficient because
                  (a) you need to do some extra steps, which the macro side-steps by
                  directly pasting the code into the proper place, and
                  (b) FORMATTER is a macro which lets you compile a format string into
                  a function, and this cannot be used in the functional version,
                  since you cannot say (FORMATTER my-control-string) but must supply
                  a string statically, as in (FORMATTER "my control string").
                  Could FORMATTER be implemented functionally? Probably, but either
                  you require the use of the Lisp compiler at run-time, which is
                  certainly possible though heavyweight usually, or you write a
                  custom compiler for that function. If you haven't figured it out
                  yet, Lispers like to leverage existing resources =)

                  4. The macro arranges all the relevant information about a machine instruction
                  in a simple way that is easy to write even if you don't understand
                  the underlying system. If you know anything about assembly language,
                  it is probably pretty easy to figure out what information is being encoded.


                  Here's another fun macro which I've been using as of yesterday afternoon,
                  courtesy of Faré Rideau:

                  (match s
                  ...
                  ((ir move (as temp (ir temp _)) b)
                  (reorder-stm (list b)
                  (mlambda ((list b) ;; match + lambda
                  (make-ir-move temp b)))))
                  ...)

                  MATCH performs ML/Erlang-style pattern matching with a Lispy twist: patterns
                  are of the form: literal, variable, or (designator ...) where designator is a
                  symbol specified by some defining construct.

                  I wrote this to act like the ML `as' [meta-?]pattern:

                  (define-macro-matcher as
                  ;; I think this lambda should be folded into the macro, but whatever
                  #'(lambda (var pat)
                  (multiple-value-bind (matcher vars)
                  (pattern-matcher pat)
                  (values `#'(lambda (form)
                  (m%and (funcall ,matcher form)
                  (setf ,var form)))
                  (merge-matcher-variables (list vars (list var)))))))

                  for example, which at macro-expansion time computes the pattern-matching code
                  of the pat argument, adds var to the list of variables (used by MATCH), and
                  creates a function which first checks the pattern and then sets the supplied
                  (lexical) variable var to the value of the form at this point the form at this
                  point. Calling PATTERN-MATCHER yourself is quite enlightening on this:

                  * (pattern-matcher '(as x 1))
                  #'(LAMBDA (FORM)
                  (M%AND (FUNCALL #'(LAMBDA (#:FORM) (M%WHEN (EQL #:FORM '1))) FORM)
                  (SETF X FORM)))
                  (X)

                  MATCH (really implemented in terms of IFMATCH) computes this at macro-expansion
                  and the Lisp statically compiles it afterwards. Of course, MATCH could be
                  implemented functionally, but consider the IR matcher that
                  (a) looks up the first parameter in a table (created by another macro) to
                  see if it is a valid IR type and get the slot names
                  (b) which are used to create slot-accessing forms that can be optimized
                  by a decent CLOS implementation when the slot-name is a literal value
                  (as when constructed by the macro, something a functional version
                  could not do).

                  Not to mention that a functional version would have to look something like:

                  (match value
                  '(pattern involving x, y, and z) #'(lambda (x y z) ...)
                  ... ...)

                  Rather annoying, don't you think? The variables need to be repeated.

                  The functional version would have to create some kind of structure to hold the
                  bound variable values and construct a list to apply the consequent function
                  with. The macro version can get away with modifying lexical variables.

                  Also the macro version can be extended to support multiple value forms, which
                  in Lisp are not first-class (but more efficient than returning lists).


                  A third quick example:

                  (ir-sequence
                  (make-ir-move ...)
                  (make-ir-jump ...)
                  ...)

                  Which transforms a list of values into a list-like data structure. I wrote
                  this originally as a macro, because in my mind it was a static transformation.
                  I realized later that it could be implemented as a function, without changing
                  any uses, but I didn't because
                  (a) I wasn't using it with higher-order functions, or situations demanding
                  them.
                  (b) It would now have to cons a list every call and do the transformation;
                  added overhead and the only gain being that it was now a function which
                  I never even used in a functional way. Rather questionable.
                  (c) I can always write a separate functional version if I need it.


                  Basically, this boils down to:

                  * Macros can do ``compile-time meta-programming'' or whatever the buzzword
                  is these days, and those above are some real-life examples.
                  This allows for compiler optimization and static analysis where desired.
                  * Macros make syntax much more convenient and less cluttered. I really
                  don't understand the people who think that macros make things harder to read.
                  It is far better to have clear labelled markers in the source code rather
                  than having to sort through boilerplate to figure out the intended meaning
                  of code. Just because I understand lambda calculus doesn't mean I want to
                  sort through nested lambdas just to use some functionality, every time.
                  If you are afraid because you are unsure of what the macro does, or its
                  complete syntax, MACROEXPAND-1 is your friend. That, and an editor with
                  some hot-keys to find source/docs/expansion/etc.

                  --
                  ; Matthew Danish <mdanish@andrew .cmu.edu>
                  ; OpenPGP public key: C24B6010 on keyring.debian. org
                  ; Signed or encrypted mail welcome.
                  ; "There is no dark side of the moon really; matter of fact, it's all dark."

                  Comment

                  • Raymond Wiker

                    Re: Python syntax in Lisp and Scheme (macro tangent)

                    Another example:

                    Given a set of files containing database data, I want to create

                    - classes that represent (the interesting bits of) each table

                    - functions that parse lines from the files, create instances
                    of a given class, and returns the instance along with the "primary
                    key" of the instance.

                    The interface to this functionality is the macro

                    (defmacro define-record (name key args &body body)
                    ...)

                    which I use like this:

                    (define-record category oid ((oid 0 integer)
                    (name 1 string)
                    (status 4 integer)
                    (deleted 5 integer)
                    (parent 9 integer)
                    active)
                    (unless (zerop deleted)
                    (return t)))

                    which expands into

                    (PROGN
                    (DEFCLASS CATEGORY-CLASS
                    NIL
                    ((OID :INITARG :OID) (NAME :INITARG :NAME) (STATUS :INITARG :STATUS)
                    (DELETED :INITARG :DELETED) (PARENT :INITARG :PARENT)
                    (ACTIVE :INITARG :ACTIVE)))
                    (DEFUN HANDLE-CATEGORY (#:LINE-2524)
                    (WHEN #:LINE-2524
                    (LET ((#:FIELDS-2525
                    (SPLIT-LINE-COLLECT #:LINE-2524
                    '((0 . INTEGER) (1 . STRING) (4 . INTEGER)
                    (5 . INTEGER) (9 . INTEGER)))))
                    (WHEN #:FIELDS-2525
                    (PROGV
                    '(OID NAME STATUS DELETED PARENT)
                    #:FIELDS-2525
                    (BLOCK NIL
                    (LET (ACTIVE)
                    (UNLESS (ZEROP DELETED) (RETURN T))
                    (VALUES OID
                    (MAKE-INSTANCE 'CATEGORY-CLASS
                    :OID
                    OID
                    :NAME
                    NAME
                    :STATUS
                    STATUS
                    :DELETED
                    DELETED
                    :PARENT
                    PARENT
                    :ACTIVE
                    ACTIVE))))))))) )

                    The implementation of this macro is probably not perfect (I've
                    learnt more about Common Lisp since I wrote it). This is OK, since I
                    can go back and change the innards of the macro whenever I want to :-)
                    Actually, this is probably something that calls for the use of MOP.

                    --
                    Raymond Wiker Mail: Raymond.Wiker@f ast.no
                    Senior Software Engineer Web: http://www.fast.no/
                    Fast Search & Transfer ASA Phone: +47 23 01 11 60
                    P.O. Box 1677 Vika Fax: +47 35 54 87 99
                    NO-0120 Oslo, NORWAY Mob: +47 48 01 11 60

                    Try FAST Search: http://alltheweb.com/

                    Comment

                    • Erann Gat

                      Re: Python syntax in Lisp and Scheme

                      In article <blr1cq$bb1$1@e nyo.uwa.edu.au> , gregm@cs.uwa.ed u.au wrote:
                      [color=blue]
                      > In comp.lang.funct ional Erann Gat[/color]
                      <my-first-name.my-last-name@jpl.nasa.g ov> wrote:[color=blue]
                      > :> I can't see why a LISP programmer would even want to write a macro.
                      > : That's because you are approaching this with a fundamentally flawed
                      > : assumption. Macros are mainly not used to make the syntax prettier
                      > : (though they can be used for that). They are mainly used to add features
                      > : to the language that cannot be added as functions.
                      >
                      > Really? Turing-completeness and all that... I presume you mean "cannot
                      > so easily be added as functions", but even that would surprise me.[/color]

                      No, I meant what I wrote. Turing-completeness is a red herring with
                      respect to a discussion of programming language features. If it were not
                      then there would be no reason to program in anything other than machine
                      language.

                      [color=blue]
                      > : For example, imagine you want to be able to traverse a binary tree and do
                      > : an operation on all of its leaves. In Lisp you can write a macro that
                      > : lets you write:
                      > : (doleaves (leaf tree) ...)
                      > : You can't do that in Python (or any other langauge).
                      >
                      > My Lisp isn't good enough to answer this question from your code,
                      > but isn't that equivalent to the Haskell snippet: (I'm sure
                      > someone here is handy in both languages)
                      >
                      > doleaves f (Leaf x) = Leaf (f x)
                      > doleaves f (Branch l r) = Branch (doleaves f l) (doleaves f r)
                      >
                      > I'd be surprised if Python couldn't do the above, so maybe doleaves
                      > is doing something more complex than it looks to me to be doing.[/color]

                      You need to change your mode of thinking. It is not that other languages
                      cannot do what doleaves does. It is that other langauges cannot do what
                      doleaves does in the way that doleaves does it, specifically allowing you
                      to put the code of the body in-line rather than forcing you to construct a
                      function.

                      Keep in mind also that this is just a trivial example. More sophisticated
                      examples don't fit well in newsgroup postings. Come see my ILC talk for
                      an example of what you can do with macros in Lisp that you will find more
                      convincing.
                      [color=blue]
                      > : Here's another example of what you can do with macros in Lisp:
                      >
                      > : (with-collector collect
                      > : (do-file-lines (l some-file-name)
                      > : (if (some-property l) (collect l))))
                      >
                      > : This returns a list of all the lines in a file that have some property.
                      >
                      > OK, that's _definitely_ just a filter: filter someproperty somefilename
                      > Perhaps throw in a fold if you are trying to abstract "collect".[/color]

                      The net effect is a filter, but again, you need to stop thinking about the
                      "what" and start thinking about the "how", otherwise, as I said, there's
                      no reason to use anything other than machine language.
                      [color=blue]
                      > : DO-FILE-LINES and WITH-COLLECTOR are macros, and they can't be implemented
                      > : any other way because they take variable names and code as arguments.
                      >
                      > What does it mean to take a variable-name as an argument? How is that
                      > different to taking a pointer? What does it mean to take "code" as an
                      > argument? Is that different to taking a function as an argument?[/color]

                      These questions are answered in various books. Go seek them out and read
                      them. Paul Graham's "On Lisp" is a good place to start.

                      E.

                      Comment

                      • David Mertz

                        Re: Python syntax in Lisp and Scheme

                        |> def posneg(filter,i ter):
                        |> results = ([],[])
                        |> for x in iter:
                        |> results[not filter(x)].append(x)
                        |> return results
                        |> collect_pos,col lect_neg = posneg(some_pro perty, some_file_name)

                        Pascal Costanza <costanza@web.d e> wrote previously:
                        |What about dealing with an arbitrary number of filters?

                        Easy enough:

                        def categorize_excl usive(filters, iter):
                        results = tuple([[] for _ in len(filters)])
                        for x in iter:
                        for n, filter in enumerate(filte rs):
                        if filter(x):
                        results[n].append(x)
                        break
                        return results

                        Or if you want to let things fall in multiple categories:

                        def categorize_incl usive(filters, iter):
                        results = tuple([[] for _ in len(filters)])
                        for x in iter:
                        for n, filter in enumerate(filte rs):
                        if filter(x):
                        results[n].append(x)
                        return results

                        Or if you want something to satisfy ALL the filters:

                        def categorize_comp ose(filters, iter):
                        results = tuple([[] for _ in len(filters)])
                        for x in iter:
                        results[compose(filters )(x)].append(x)
                        return results

                        The implementation of 'compose()' is left as an exercise to readers :-).
                        Or you can buy my book, and read the first chapter.

                        Yours, David...

                        --
                        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.
                        --
                        Buy Text Processing in Python: http://tinyurl.com/jskh

                        Comment

                        • David Mertz

                          Re: Python syntax in Lisp and Scheme

                          |> def posneg(filter,i ter):
                          |> results = ([],[])
                          |> for x in iter:
                          |> results[not filter(x)].append(x)
                          |> return results
                          |> collect_pos,col lect_neg = posneg(some_pro perty, some_file_name)

                          Pascal Costanza <costanza@web.d e> wrote previously:
                          |What about dealing with an arbitrary number of filters?

                          Easy enough:

                          def categorize_excl usive(filters, iter):
                          results = tuple([[] for _ in len(filters)])
                          for x in iter:
                          for n, filter in enumerate(filte rs):
                          if filter(x):
                          results[n].append(x)
                          break
                          return results

                          Or if you want to let things fall in multiple categories:

                          def categorize_incl usive(filters, iter):
                          results = tuple([[] for _ in len(filters)])
                          for x in iter:
                          for n, filter in enumerate(filte rs):
                          if filter(x):
                          results[n].append(x)
                          return results

                          Or if you want something to satisfy ALL the filters:

                          def categorize_comp ose(filters, iter):
                          results = tuple([[] for _ in len(filters)])
                          for x in iter:
                          results[compose(filters )(x)].append(x)
                          return results

                          The implementation of 'compose()' is left as an exercise to readers :-).
                          Or you can buy my book, and read the first chapter.

                          Yours, David...

                          --
                          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.
                          --
                          Buy Text Processing in Python: http://tinyurl.com/jskh


                          Comment

                          • Kenny Tilton

                            Re: Python syntax in Lisp and Scheme



                            Hannu Kankaanp?? wrote:
                            [color=blue]
                            > The problem with the example arises from the fact that indentation
                            > is used for human readability, but parens are used by the parser.[/color]

                            And by the editor, meaning the buggy code with the extra parens had not
                            been written in a parens-aware editor (or the coder had stuck a parens
                            on without kicking off a re-indentation).
                            [color=blue]
                            > A clash between these two representations can lead to subtle bugs
                            > like this one. But remove one of the representations , and there
                            > can't be clashes.[/color]

                            No need. Better yet, with parens you do not have to do the indentation
                            yourself, you just have to look at what you are typing. Matching parens
                            highlight automatically as you close up nested forms (it's kinda fun
                            actually), and then a single key chard re-indents (if you have been
                            refactoring and things now belong at diff indentation levels).

                            I used to spend a /lot/ of time on indentation (in other languages). No
                            more. That is just one of the advantages of all those parentheses.

                            kenny

                            Comment

                            • Pascal Bourguignon

                              Re: Python syntax in Lisp and Scheme


                              Marcin 'Qrczak' Kowalczyk <qrczak@knm.org .pl> writes:[color=blue]
                              > The main disadvantage of macros is that they either force the syntax
                              > to look like Lisp, or the way to present code snippets to macros is
                              > complicated (Template Haskell), or they are as limited as C preprocessor
                              > (which can't examine parameters).
                              >
                              > I find the Lisp syntax hardly readable when everything looks alike,
                              > mostly words and parentheses, and when every level of nesting requires
                              > parens. I understand that it's easier to work with by macros, but it's
                              > harder to work with by humans like I.[/color]

                              I don't understand what you're complaining about.

                              When you have macros such as loop that allow you to write stuff like:

                              (loop for color in '(blue white red)
                              with crosses = :crosses
                              collect (rgb color) into rgb-list
                              maximize (blue-component color) into max-blue
                              until (color-pleases-user color)
                              finally return (vlues color rgb-list max-blue))

                              where are the parentheses at EVERY level you're complaining about?
                              where is the lisp-like syntax?


                              Lisp is not commie-stuff, nobody forces you to program your macros
                              following any hypothetical party line.

                              --
                              __Pascal_Bourgu ignon__

                              Do not adjust your mind, there is a fault in reality.

                              Comment

                              • David Mertz

                                Re: Python syntax in Lisp and Scheme

                                My answer sucked in a couple ways.

                                (1) As Bengt Ricther pointed out up-thread, I should have changed David
                                Eppstein's names 'filter' and 'iter' to something other than the
                                built-in names.

                                (2) The function categorize_comp ose() IS named correctly, but it doesn't
                                DO what I said it would. If you want to fulfill ALL the filters, you
                                don't to compose them, but... well, 'all()' them:

                                | def categorize_join tly(preds, it):
                                | results = [[] for _ in len(preds)]
                                | for x in it:
                                | results[all(filters)(x)].append(x)
                                | return results

                                Now if you wonder what the function 'all()' does, you could download:



                                But the relevant part is:

                                from operator import mul, add, truth
                                apply_each = lambda fns, args=[]: map(apply, fns, [args]*len(fns))
                                bools = lambda lst: map(truth, lst)
                                bool_each = lambda fns, args=[]: bools(apply_eac h(fns, args))
                                conjoin = lambda fns, args=[]: reduce(mul, bool_each(fns, args))
                                all = lambda fns: lambda arg, fns=fns: conjoin(fns, (arg,))

                                For 'lazy_all()', look at the link.

                                See, Python is Haskell in drag.

                                Yours, David...

                                --
                                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

                                Working...