For Kenny Tilton: Why do I need macros revisited.

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Chris Reedy

    For Kenny Tilton: Why do I need macros revisited.

    For everyone -

    Apologies for the length of this message. If you don't want to look
    at the long example, you can skip to the end of the message.

    And for the Python gurus among you, if you can spare the time, I
    would appreciate any comments (including words like evil and disgusting,
    if you think they are applicable :-}) on the example here.

    Kenny -

    I asked my question about macros with some malice aforethought. This
    is a topic I've thought about in the past.
    [color=blue]
    > Andrew Dalke wrote:
    >[color=green]
    >> Kenny Tilton:
    >>[color=darkred]
    >>> This macro:
    >>>
    >>> (defmacro c? (&body code)
    >>> `(let ((cache :unbound))
    >>> (lambda (self)
    >>> (declare (ignorable self))
    >>> (if (eq cache :unbound)
    >>> (setf cache (progn ,@code))
    >>> cache))))[/color]
    >>
    >>
    >>
    >> I have about no idea of what that means. Could you explain
    >> without using syntax? My guess is that it caches function calls,
    >> based only on the variable names. Why is a macro needed
    >> for that?[/color][/color]

    I sympathize with Andrew on this. I had to study this and the following
    code for awhile before I figured out what you are doing. However, I do
    have an advantage, I know lisp and the macro system and just how
    powerful the macro system is.
    [color=blue]
    > (defun get-cell (self slotname) ;; this fn does not need duplicating
    > (let ((sv (slot-value self slotname)))
    > (typecase sv
    > (function (funcall sv self))
    > (otherwise sv))))
    >
    > (defmethod right ((self box)) ;; this needs duplicating for each slot
    > (get-cell box right))
    >
    > But I just hide it all (and much more) in:
    >
    > (defmodel box ()
    > ((left :initarg :left :accessor left)
    > (right :initarg :right :accessor right)))
    >
    > ....using another macro:
    >
    > (defmacro defmodel (class superclasses (&rest slots))
    > `(progn
    > (defclass ,class ,superclasses
    > ,slots)
    > ,@(mapcar (lambda (slot)
    > (destructuring-bind
    > (slotname &key initarg accessor)
    > slot
    > (declare (ignore slotname initarg))
    > `(defmethod ,accessor ((self ,class))
    > (get-cell self ',slotname))))
    > slots)))[/color]

    Ok. The following is more lines of code than you have here. On the other
    hand, I think it does about the same thing:

    <Example>

    class cellvalue(objec t):
    def __init__(self):
    self._fn = None
    def _get_value(self , obj):
    if hasattr(self, '_value'):
    return self._value
    else:
    value = self._fn
    if callable(self._ fn):
    value = value(obj)
    self._value = value
    return value
    def _set_value(self , value):
    self._value = value
    def _del_value(self ):
    del self._value
    def _set_fn(self, fn):
    self._fn = fn
    if hasattr(self, '_value'):
    self._del_value ()

    class modelproperty(o bject):
    def _init_cell(self , obj):
    obj.__dict__[self.name] = cellvalue()
    def __get__(self, obj, cls):
    if obj is None:
    return self
    else:
    return obj.__dict__[self.name]._get_value(obj )
    def __set__(self, obj, val):
    obj.__dict__[self.name]._set_value(val )
    def __delete__(self , obj):
    obj.__dict__[self.name]._del_value()
    def setfn(self, obj, fn):
    obj.__dict__[self.name]._set_fn(fn)
    def setname(self, name):
    self.name = name
    self.__doc__ = 'Model Property '+str(name)

    class modeltype(type) :
    def __init__(cls, name, bases, dict):
    super(modeltype , cls).__init__(n ame, bases, dict)
    modelprops = []
    for attr, decl in dict.items():
    if isinstance(decl , modelproperty):
    decl.setname(at tr)
    modelprops.appe nd(attr)
    if modelprops:
    __originit = getattr(cls, '__init__')
    def _modeltype_init (self, *args, **kw):
    for attr in modelprops:
    getattr(self.__ class__, attr)._init_cel l(self)
    if __originit is not None:
    __originit(self , *args, **kw)
    setattr(cls, '__init__', _modeltype_init )
    [color=blue][color=green][color=darkred]
    >>> class foo:[/color][/color][/color]
    .... __metaclass__ = modeltype
    .... x = modelproperty()
    .... def __init__(self, x=None):
    .... self.__class__. x.setfn(self, x)[color=blue][color=green][color=darkred]
    >>> z = foo(x=lambda self: self.a + 2)
    >>> z.a = 5
    >>> print z.x[/color][/color][/color]
    7[color=blue][color=green][color=darkred]
    >>> z.x = -3
    >>> print z.x[/color][/color][/color]
    -3[color=blue][color=green][color=darkred]
    >>> z.a = 15
    >>> print z.x[/color][/color][/color]
    -3[color=blue][color=green][color=darkred]
    >>> del z.x
    >>> print z.x[/color][/color][/color]
    17

    I think that has most of the behavior you were looking for. As you can
    see from the example, I leaned (I'm not sure leaned is a strong enough
    work :-)) on the newer capabilities for metaclasses and descriptors.
    (And learned a lot about exactly how they work by writing this up!)

    </Example>

    Having looked at the two pieces of code, the only thing that struck me
    about how they're used is that the lambda expression needed in the
    Python version is clunkier than the version in the Lisp version. On the
    other hand, that might be addressed by a somewhat more elegant syntax in
    Python for constant code blocks, something that's been mentioned by
    others in recent messages.

    Even though the Python setup (with two classes and a metaclass) is
    longer than the Lisp version, I'm not sure it's any clunkier or harder
    to understand.

    So back to my original question, why do I want macros in Python?

    Let me provide a candidate answer and rebuttal:

    The real reason I want to do macros in Lisp is that they allow me to
    easily write new custom languages. Would a sufficiently powerful macro
    facility in Python allow me to do this? I suspect that the answer to
    this question would only be yes if that included some sort of parser
    generator facility.

    Expanding on that: One of the nice things about Python (at least for
    those like me who like the language) is the clean syntax. However, that
    comes at a price: Needing a real parser to parse the language.

    Lisp on the other hand has an extremely simple syntax that doesn't
    require a real parser. That allows me to create whole new "syntaxes" in
    lisp, since I'm not really changing the syntax, just changing how a
    given set of S-expressions are interpreted.

    On the other hand, if I'm going to go to the complexity of including a
    parser generator so I can generate my own custom languages, it sounds to
    me like I'm about to reproduce what the Perl/Parrot people are up to. (I
    admit that I'd really like the time to look at what they're doing more
    deeply.)

    Which brings me back to my original question: Would a macro facility in
    Python really buy me anything? And, in view of Alex's arguments, would
    that benefit outweigh the potential significant costs in other areas?

    Chris



    -----= Posted via Newsfeeds.Com, Uncensored Usenet News =-----
    http://www.newsfeeds.com - The #1 Newsgroup Service in the World!
    -----== Over 100,000 Newsgroups - 19 Different Servers! =-----
  • Kenny Tilton

    #2
    Re: For Kenny Tilton: Why do I need macros revisited.



    Chris Reedy wrote:[color=blue]
    > For everyone -
    >
    > Apologies for the length of this message. If you don't want to look at
    > the long example, you can skip to the end of the message.
    >
    > And for the Python gurus among you, if you can spare the time, I would
    > appreciate any comments (including words like evil and disgusting, if
    > you think they are applicable :-}) on the example here.
    >
    > Kenny -
    >
    > I asked my question about macros with some malice aforethought. This
    > is a topic I've thought about in the past.
    >[color=green]
    >> Andrew Dalke wrote:
    >>[color=darkred]
    >>> Kenny Tilton:
    >>>
    >>>> This macro:
    >>>>
    >>>> (defmacro c? (&body code)
    >>>> `(let ((cache :unbound))
    >>>> (lambda (self)
    >>>> (declare (ignorable self))
    >>>> (if (eq cache :unbound)
    >>>> (setf cache (progn ,@code))
    >>>> cache))))
    >>>
    >>>
    >>>
    >>>
    >>> I have about no idea of what that means. Could you explain
    >>> without using syntax? My guess is that it caches function calls,
    >>> based only on the variable names. Why is a macro needed
    >>> for that?[/color]
    >>[/color]
    >
    > I sympathize with Andrew on this. I had to study this and the following
    > code for awhile before I figured out what you are doing. However, I do
    > have an advantage, I know lisp and the macro system and just how
    > powerful the macro system is.
    >[color=green]
    >> (defun get-cell (self slotname) ;; this fn does not need duplicating
    >> (let ((sv (slot-value self slotname)))
    >> (typecase sv
    >> (function (funcall sv self))
    >> (otherwise sv))))
    >>
    >> (defmethod right ((self box)) ;; this needs duplicating for each slot
    >> (get-cell box right))
    >>
    >> But I just hide it all (and much more) in:
    >>
    >> (defmodel box ()
    >> ((left :initarg :left :accessor left)
    >> (right :initarg :right :accessor right)))
    >>
    >> ....using another macro:
    >>
    >> (defmacro defmodel (class superclasses (&rest slots))
    >> `(progn
    >> (defclass ,class ,superclasses
    >> ,slots)
    >> ,@(mapcar (lambda (slot)
    >> (destructuring-bind
    >> (slotname &key initarg accessor)
    >> slot
    >> (declare (ignore slotname initarg))
    >> `(defmethod ,accessor ((self ,class))
    >> (get-cell self ',slotname))))
    >> slots)))[/color]
    >
    >
    > Ok. The following is more lines of code than you have here. On the other
    > hand, I think it does about the same thing:
    >
    > <Example>
    >
    > class cellvalue(objec t):
    > def __init__(self):
    > self._fn = None
    > def _get_value(self , obj):
    > if hasattr(self, '_value'):
    > return self._value
    > else:
    > value = self._fn
    > if callable(self._ fn):
    > value = value(obj)
    > self._value = value
    > return value
    > def _set_value(self , value):
    > self._value = value
    > def _del_value(self ):
    > del self._value
    > def _set_fn(self, fn):
    > self._fn = fn
    > if hasattr(self, '_value'):
    > self._del_value ()
    >
    > class modelproperty(o bject):
    > def _init_cell(self , obj):
    > obj.__dict__[self.name] = cellvalue()
    > def __get__(self, obj, cls):
    > if obj is None:
    > return self
    > else:
    > return obj.__dict__[self.name]._get_value(obj )
    > def __set__(self, obj, val):
    > obj.__dict__[self.name]._set_value(val )
    > def __delete__(self , obj):
    > obj.__dict__[self.name]._del_value()
    > def setfn(self, obj, fn):
    > obj.__dict__[self.name]._set_fn(fn)
    > def setname(self, name):
    > self.name = name
    > self.__doc__ = 'Model Property '+str(name)
    >
    > class modeltype(type) :
    > def __init__(cls, name, bases, dict):
    > super(modeltype , cls).__init__(n ame, bases, dict)
    > modelprops = []
    > for attr, decl in dict.items():
    > if isinstance(decl , modelproperty):
    > decl.setname(at tr)
    > modelprops.appe nd(attr)
    > if modelprops:
    > __originit = getattr(cls, '__init__')
    > def _modeltype_init (self, *args, **kw):
    > for attr in modelprops:
    > getattr(self.__ class__, attr)._init_cel l(self)
    > if __originit is not None:
    > __originit(self , *args, **kw)
    > setattr(cls, '__init__', _modeltype_init )
    >[color=green][color=darkred]
    > >>> class foo:[/color][/color]
    > ... __metaclass__ = modeltype
    > ... x = modelproperty()
    > ... def __init__(self, x=None):
    > ... self.__class__. x.setfn(self, x)[color=green][color=darkred]
    > >>> z = foo(x=lambda self: self.a + 2)
    > >>> z.a = 5
    > >>> print z.x[/color][/color]
    > 7[color=green][color=darkred]
    > >>> z.x = -3
    > >>> print z.x[/color][/color]
    > -3[color=green][color=darkred]
    > >>> z.a = 15
    > >>> print z.x[/color][/color]
    > -3[color=green][color=darkred]
    > >>> del z.x
    > >>> print z.x[/color][/color]
    > 17
    >
    > I think that has most of the behavior you were looking for. As you can
    > see from the example, I leaned (I'm not sure leaned is a strong enough
    > work :-)) on the newer capabilities for metaclasses and descriptors.
    > (And learned a lot about exactly how they work by writing this up!)[/color]

    <g> looks a lot like the code I was writing when I began a Python port
    of my Cells project. I'll be open-sourcing the Lisp version soon, you
    can do the Python port. :)

    You are absolutely right. Metaclasses are killer. I am surprised
    Pythonistas afraid of macros let them into the language! I actually had
    a metaclass implementation of Cells until I decided to release the
    source. The MOP is not part of the standard, and it shows across
    implementations . Hell, MCL does not even expose a MOP.
    [color=blue]
    >
    > </Example>
    >
    > Having looked at the two pieces of code, the only thing that struck me
    > about how they're used is that the lambda expression needed in the
    > Python version is clunkier than the version in the Lisp version.[/color]

    You will be delighted to know that one of Lisp priesthood sees no need
    for macros since what they do can be done with lambdas. Not sure if that
    is so where one is generating multiple top-level forms from one clause.
    Me, I like hiding implementation details as mush as possible, and having
    just one place to go when changing how something works.

    As for the lambda being clunkier, un-hunh, and if you decide to change
    the mechanism after a lot of them have been coded, perhaps passing a
    second argument, here comes the mega-edit. Worse, what happens when the
    toy hack reaches maturity and you get the final version of the macro:

    this:
    (c? (+ 10 (left self)))

    expands to:
    (make-c-dependent
    :code '((+ 10 (left self)))
    :rule (lambda (c &aux (self (c-model c)))
    (+ 10 (left self))))

    One funny thing is that even if one open codes that, the readers you all
    are so worried about still do not know what C-DEPENDENT is.

    Now picture a make-instance with five of those in a row. The text widget
    font is a function of a user preference, all four dimensions are a
    function of the font size and string length, the color may be a function
    of sysntax judgment for highlighting, etc etc. Now you cannot see the
    semantics for all the redundant, essentially meaningless wiring.
    [color=blue]
    > So back to my original question, why do I want macros in Python?[/color]

    Hiding the wiring, where a function will not do because the argument is
    your source code.
    [color=blue]
    >
    > Let me provide a candidate answer and rebuttal:
    >
    > The real reason I want to do macros in Lisp is that they allow me to
    > easily write new custom languages.[/color]

    No, that is not a big reason. It is cool that one could do that readily
    if one stuck to the basic sexpr notation, but my experience to date is
    that I do not need a wholly new language as long as I can drop into new
    syntax (c?...) periodically to get what I would have created in a wholly
    new embedded language.
    [color=blue]
    > Which brings me back to my original question: Would a macro facility in
    > Python really buy me anything? And, in view of Alex's arguments, would
    > that benefit outweigh the potential significant costs in other areas?[/color]

    Lispniks have not seen code become unreadable because of macros. That is
    something you all (well, most) are imagining. You are almost positing it
    as given. And it is simply not so. We have pointed out again and again
    that macros are no harder to understand than functions or classes, but
    no one addresses that point. Some say "I want to see all the legal
    Pythion instructions". Except when it is in a function, I guess.
    Strangely, quite a few of you have also conceded macros can leverage a
    language.

    Well, it seems like we have covered everything pretty thoroughly. Back
    to RoboCup!

    --

    kenny tilton
    clinisys, inc

    ---------------------------------------------------------------
    "Career highlights? I had two. I got an intentional walk from
    Sandy Koufax and I got out of a rundown against the Mets."
    -- Bob Uecker

    Comment

    • Paul Foley

      #3
      Re: For Kenny Tilton: Why do I need macros revisited.

      On Fri, 22 Aug 2003 08:09:40 GMT, Andrew Dalke wrote:
      [color=blue][color=green]
      >> Lispniks have not seen code become unreadable because of macros. That is
      >> something you all (well, most) are imagining. You are almost positing it
      >> as given. And it is simply not so.[/color][/color]
      [color=blue]
      > Terry Reedy pointed out something from some Scheme documentation
      > found by Dave Kuhlman:
      > http://www.schemers.org/Documents/St...-3.html#%_sec_
      > Temp_4
      > ] As Scheme became more widespread, local dialects began to
      > ] diverge until students and researchers occasionally found it difficult
      > ] to understand code written at other sites.[/color]
      [color=blue]
      > I cannot say if that's because of macros or other aspects of Scheme.[/color]

      Scheme, as such, is barely a language. It's pretty useless on its own.
      Most of the functionality of an actual Scheme /implementation/ is
      extra-standard stuff (i.e., not Scheme), which, naturally enough,
      every implementor does differently.

      [Scheme didn't even have macros until R4RS (1991?), and then only as
      an appendix...]
      [color=blue][color=green]
      >> We have pointed out again and again
      >> that macros are no harder to understand than functions or classes, but
      >> no one addresses that point.[/color][/color]
      [color=blue]
      > What about Terry's comment, based on the above URL:
      > ) Reading the third referenced page on Macros, I notice that the amount
      > ) of syntax definition for the macro sublanguage is as large as a
      > ) substantial portion (one-third?) of that for core Python (if condensed
      > ) to the same density). So, just by definitional bulk, having it in the
      > ) language would not be a free ride.[/color]

      Scheme macros are not the same as Lisp macros. Scheme macros are a
      lot more complicated (and less useful; but most Scheme implementations
      also offer Lisp-style macros...)


      --
      Just because we Lisp programmers are better than everyone else is no
      excuse for us to be arrogant. -- Erann Gat

      (setq reply-to
      (concatenate 'string "Paul Foley " "<mycroft" '(#\@) "actrix.gen.nz> "))

      Comment

      • Jacek Generowicz

        #4
        Re: For Kenny Tilton: Why do I need macros revisited.

        "Andrew Dalke" <adalke@mindspr ing.com> writes:
        [color=blue]
        > http://www.schemers.org/Documents/St...-3.html#%_sec_
        > Temp_4
        > ] As Scheme became more widespread, local dialects began to
        > ] diverge until students and researchers occasionally found it difficult
        > ] to understand code written at other sites.[/color]

        That has probably more to do with the fact that Scheme is
        minimalistic. And if you have a minimalistic langugage, you end up
        having to implement a lot of utilities before you can get on with what
        you are actulally trying to achieve (or have your language
        implementation provide them as extensions).

        Schemers criticize Common Lisp for being too big. The consequence of
        having a big language (a la CL, not a la C++) is that most things that
        "everybody" needs are already in the language. In Scheme "everybody"
        ends up re-inventing the things that "everybody" needs, separately,
        leading to fragmentation. In CL, everybody agrees on how to implement
        the things that "everybody" needs: you use the ones defined by the
        standard. In this way, any macro-magic is restricted to the domain
        specific corners of your application.

        In summary, I reckon that any inter-Scheme incomprehensibi lity or
        Scheme fragmentation results from starting with a language that
        doesn't offer enough out of the box.

        Comment

        • Terry Reedy

          #5
          Re: For Kenny Tilton: Why do I need macros revisited.


          "Paul Foley" <see@below.inva lid> wrote in message
          news:m24r09vqbr .fsf@mycroft.ac trix.gen.nz...[color=blue]
          > Scheme, as such, is barely a language. It's pretty useless on its[/color]
          own.[color=blue]
          > Most of the functionality of an actual Scheme /implementation/ is
          > extra-standard stuff (i.e., not Scheme), which, naturally enough,
          > every implementor does differently.[/color]

          Core Python, while useful on it own, is also pretty sparse. So I
          gather it would be something like having multiple Python
          implementations (of comparable popularity) with different sets of
          builtins and overlapping but incompatible 'standard' libraries. The
          Python community is fortunate to have avoided that.

          ....[color=blue]
          > Scheme macros are not the same as Lisp macros. Scheme macros are a
          > lot more complicated (and less useful; but most Scheme[/color]
          implementations[color=blue]
          > also offer Lisp-style macros...)[/color]

          Please excuse my confusing of Scheme with Lisp. I am pleased to find
          that my difficulty in reading the Scheme macro stuff wasn't just me.
          But note that there have been proposals that if Python were to have a
          macro facility, it should be 'hygenic', which I presume means like
          Scheme macros.

          Until some advocate of a Python macro facility adds more detail to the
          proposal beyound 'Lisp/Scheme-like maco facility', it is really hard
          for someone like me, who has used neither, to have much of any
          concrete idea of what is being proposed.

          Terry J. Reedy


          Comment

          • Kenny Tilton

            #6
            Re: For Kenny Tilton: Why do I need macros revisited.



            Andrew Dalke wrote:[color=blue]
            > Kenny Tilton:
            >[color=green]
            >>We have pointed out again and again
            >>that macros are no harder to understand than functions or classes, but
            >>no one addresses that point.[/color]
            >
            >
            > What about Terry's comment, based on the above URL:
            > ) Reading the third referenced page on Macros, I notice that the amount
            > ) of syntax definition for the macro sublanguage is as large as a
            > ) substantial portion (one-third?) of that for core Python (if condensed
            > ) to the same density). So, just by definitional bulk, having it in the
            > ) language would not be a free ride.[/color]

            Oy. This comment is about understanding how to write macros. We are
            talking about whether:

            (with-open-file (f "my.data" <...options...> )
            (do-fun-things-with f))

            ....is harder to understand than:

            (open-file-and-do "my.data"
            <...options.. .>
            :do-this (lambda (f) (do-fun-things-with f)))

            btw, /writing/ macros takes a while to learn, or it did for me anyway,
            because one has moved to a different space than a programmer normally
            occupies, somewhere inside the compiler you might say. So some of the
            time you are typing in code for run-time and some of the time you are
            typing in code that runs at compile time to produce the code that runs
            at runtime. And there's some weird syntax, with backquotes and coomas
            and ampersands. Great fun, once it is second nature, but till then...the
            neat thing is realizing you can put in debug statements that execute
            while the macro is being expanded, not at run time. And you can have a
            bug in the expanding code such that evaluating the form dies before it
            begins being evaluated! <g>
            [color=blue]
            >
            >[color=green]
            >>Strangely, quite a few of you have also conceded macros can leverage a
            >>language.[/color]
            >
            >
            > Leverage a language ... for what? And for whom?[/color]

            The keystone macro of the RoboCup client I plan to share with soccer
            hooligans everywhere is DEFTASK:

            (deftask <taskname> &key achieved subtasks wait-on-subtasks?
            attempt retry-when)

            achieved is a rule for deciding when the task has been achieved.

            subtasks are subtasks to be completed (achieved) before the task at hand
            is attempted, unless...

            wait-on-subtasks? is nil, in which case the task can decide on its won
            when to check if it has alreadt been achieved (you'll need an example).

            attempt is code which generates a command to the soccer server,
            hopefully leading to task achievement

            retry-when tells the engine when to try again if not yet achieved. eg,
            don't turn again to look for the ball until we have gotten a new "see"
            message.

            Now that's pretty slim doc, but there will be more and examples galore
            (and an on-line help desk <g>), but some points:

            No, no one looking at my code has ever seen deftask before. But if they
            have done any lisp at all, they will know I have built a little task
            solving engine for them. They will know because I used standard Lisp
            terminology, the "def" prefix. They will understand all the keywords,
            but immediately scream for documentation because keywords do not a
            user's guide make. They will also see that the style is declarative,
            which is meant to be helpful (and is) but they will sweat bullets until
            they have a solid feel for how the engine works inside ("why did a
            completed subtask start getting solved again"). I'll have to come clean
            on the guts of the engine.

            Or, as some of the folks on our team have done, they can macroexpand any
            deftask form. They can look at the source of deftask as well, but that
            can be harder because the final output is kinda disguised by all the
            code which builds the final output. Once they see the astonishing
            output, they will likely decide just to have me provide a functional
            spec so they do not have to worry about the engine internals. Like I do.

            They just write:

            (deftask head-for-ball () ;; literally set body heading for ball
            ()
            :achieved (bwhen (ball (^ball))
            (< (+ .neck. (seen-dir ball)) 10))
            :subtasks (list (mktask find-ball))
            :attempt (bwhen (ball (^ball))
            (let ((correction (+ .neck. (seen-dir ball))))
            (ptrc nil "correcting " correction) ;;debug macro!
            `(turn ,correction))))

            The unadvertised synatx above (the two () forms near the beginning, are
            a giveaway that deftask expands into the familiar (to lispniks) defclass
            form. ie, deftask is implemented as defclass. Again, I make an effort to
            keep the syntax lispy and recognizable and familiar and all that good
            stuff. They can add slots to their task, have supertasks, etc etc.

            So the defclass power is /leveraged/ to make deftask even better than i
            could make it. Generic functions automatically can be dispatched by
            soccer task, without me lifting a finger.

            In the end, a bunch of people with just an interest in machine learning
            and genetic algorithms and soccer can have some fun concnetrating just
            on the ML and GA and football. Because I am providing a task-executing
            "language" which deals with the soccer server for them.

            As for what the above would look like without macros:

            (defmodel head-for-ball (task)
            ()
            (:default-initargs
            :wait-on-subtasks-p t
            :kids (c? (let ((task self) (self (player self)))
            (mapcar (lambda (subtask)
            (if (symbolp subtask)
            (make-instance subtask :player self)
            subtask))
            (thekids (list (mktask find-ball))))))
            :achieved-body (lambda (cells::c &aux (task (cells::c-model
            cells::c)) (self (player task)))
            (declare (ignorable self task))
            (bwhen (ball (^ball))
            (< (+ .neck. (seen-dir ball)) 10)))
            :retry-when-body (lambda (cells::c &aux (task (cells::c-model
            cells::c)) (self (player task)))
            (declare (ignorable cells::c self task))
            nil)
            :attempt-body (lambda (cells::c &aux (task (cells::c-model
            cells::c)) (self (player task)))
            (declare (ignorable self task))
            (bwhen (ball (^ball))
            (let ((correction (+ .neck. (seen-dir ball))))
            (ptrc nil "head-for-ball correcting" correction)
            `(turn ,correction)))) ))

            Not too bad, but then you have to expand defmodel. :)

            --

            kenny tilton
            clinisys, inc

            ---------------------------------------------------------------
            "Career highlights? I had two. I got an intentional walk from
            Sandy Koufax and I got out of a rundown against the Mets."
            -- Bob Uecker

            Comment

            • Jacek Generowicz

              #7
              Re: For Kenny Tilton: Why do I need macros revisited.

              "Terry Reedy" <tjreedy@udel.e du> writes:
              [color=blue]
              > Until some advocate of a Python macro facility adds more detail to the
              > proposal beyound 'Lisp/Scheme-like maco facility', it is really hard
              > for someone like me, who has used neither, to have much of any
              > concrete idea of what is being proposed.[/color]

              Until some advocate of a Python macro facility adds more detail to the
              proposal ... it is really hard for me to have much of any concrete
              idea what is being proposed ... because Lisp-style macros rely on the
              fact that Lisp code is expressed in a fundamental Lisp data structure,
              in the form of its parse tree. This ain't the case in Python, so the
              whole macro business suddenly gets more complicated by an order of
              magnitude or two.

              I just can't imagine what such a macro system would look like. Maybe
              someone with deep knowledge of Dylan can enlighten us.

              Comment

              • David Mertz

                #8
                Re: For Kenny Tilton: Why do I need macros revisited.

                "Andrew Dalke" <adalke@mindspr ing.com> wrote previously:
                |I've seen David Mertz' xml_pickle code which makes good use of
                |[metaclasses], but don't yet follow how it works.

                I'm afraid I must insist here that the use of metaclasses in
                gnosis.xml.pick le is utterly trivial, and just for show. You'll
                have to look elsewhere for "good use" of them :-).

                Yours, David...

                --
                mertz@ _/_/_/_/ THIS MESSAGE WAS BROUGHT TO YOU BY: \_\_\_\_ n o
                gnosis _/_/ Postmodern Enterprises \_\_
                ..cx _/_/ \_\_ d o
                _/_/_/ IN A WORLD W/O WALLS, THERE WOULD BE NO GATES \_\_\_ z e


                Comment

                • Michele Simionato

                  #9
                  Re: For Kenny Tilton: Why do I need macros revisited.

                  Kenny Tilton <ktilton@nyc.rr .com> wrote in message news:<3F45A7BF. 4060806@nyc.rr. com>...[color=blue]
                  > You are absolutely right. Metaclasses are killer. I am surprised
                  > Pythonistas afraid of macros let them into the language![/color]

                  Me too. Actually they are quite *scaring*. In my post on
                  "PEP 312 (and thus 308) implemented with a black magic trick" actually
                  I argued that they were much *worse* than macros, since they are able
                  to change the *semantics* of the language, a much more dangerous
                  thing than simply changing the syntax. In a sense, they are deeply
                  unpythonic,
                  the exact opposite of "explicit is better than implicit".
                  Maybe it enters in "practicali ty beats purity", but this is stretching
                  the principle quite a bit. Same for descriptors and properties, which
                  still are much less dangerous.
                  I think metaclasses were intended not to be used, except from
                  developers
                  and very advanced users. The problem is that once you have a feature
                  in
                  a language, people will use it. I do like metaclasses, but I would be
                  scared
                  in debugging a large program written by others using them and with
                  poor ocumentation. Each time you see a class, you are never sure of
                  what it is
                  doing; when the bug happens, you are not sure if it is in the class or
                  in
                  the metaclass (this happened to me even with my own programs).
                  It is quite worrysome, actually. Fortunately, we are good people, here
                  on c.l.py, and I don't think anybody would mess things up, but it
                  could
                  *easily* be done.
                  Now, I trust the programmer and I do like the power and the freedom;
                  but still it strikes to me as a case of multiple personality to have
                  a language that at the surface is plain, clear, nicely indented, and
                  under the cover ... caveat emptor!

                  Let it be this way, anyway, and let us continue to advertise it as
                  a "clean" language. Let us stop people who want case statement, repeat
                  ... until, ternary operators, braces, and the like, and let us under
                  the cover give people the freedom to program classes and altering at
                  will nearly everything at the semantics level. Let the other worry
                  about syntax ...

                  ;-)

                  [color=blue]
                  > I actually had
                  > a metaclass implementation of Cells until I decided to release the
                  > source. The MOP is not part of the standard, and it shows across
                  > implementations . Hell, MCL does not even expose a MOP.
                  >[/color]

                  Quite impressive. You are actually saying that you do prefer Python
                  over
                  Lisp on a problem of ultra-high level programming which should be
                  the rightful Lisp playhouse ... To be fair, the reason is not lack of
                  power by Lisp, but lack of standardization , still it is something that
                  makes me thinking ...

                  Michele Simionato, Ph. D.
                  MicheleSimionat o@libero.it

                  --- Currently looking for a job ---

                  Comment

                  • Michele Simionato

                    #10
                    Re: For Kenny Tilton: Why do I need macros revisited.

                    Kenny Tilton <ktilton@nyc.rr .com> wrote in message news:<3F45A7BF. 4060806@nyc.rr. com>...[color=blue]
                    > You are absolutely right. Metaclasses are killer. I am surprised
                    > Pythonistas afraid of macros let them into the language![/color]

                    Me too. Actually they are quite *scaring*. In my post on
                    "PEP 312 (and thus 308) implemented with a black magic trick" actually
                    I argued that they were much *worse* than macros, since they are able
                    to change the *semantics* of the language, a much more dangerous
                    thing than simply changing the syntax. In a sense, they are deeply
                    unpythonic,
                    the exact opposite of "explicit is better than implicit".
                    Maybe it enters in "practicali ty beats purity", but this is stretching
                    the principle quite a bit. Same for descriptors and properties, which
                    still are much less dangerous.
                    I think metaclasses were intended not to be used, except from
                    developers
                    and very advanced users. The problem is that once you have a feature
                    in
                    a language, people will use it. I do like metaclasses, but I would be
                    scared
                    in debugging a large program written by others using them and with
                    poor ocumentation. Each time you see a class, you are never sure of
                    what it is
                    doing; when the bug happens, you are not sure if it is in the class or
                    in
                    the metaclass (this happened to me even with my own programs).
                    It is quite worrysome, actually. Fortunately, we are good people, here
                    on c.l.py, and I don't think anybody would mess things up, but it
                    could
                    *easily* be done.
                    Now, I trust the programmer and I do like the power and the freedom;
                    but still it strikes to me as a case of multiple personality to have
                    a language that at the surface is plain, clear, nicely indented, and
                    under the cover ... caveat emptor!

                    Let it be this way, anyway, and let us continue to advertise it as
                    a "clean" language. Let us stop people who want case statement, repeat
                    ... until, ternary operators, braces, and the like, and let us under
                    the cover give people the freedom to program classes and altering at
                    will nearly everything at the semantics level. Let the other worry
                    about syntax ...

                    ;-)

                    [color=blue]
                    > I actually had
                    > a metaclass implementation of Cells until I decided to release the
                    > source. The MOP is not part of the standard, and it shows across
                    > implementations . Hell, MCL does not even expose a MOP.
                    >[/color]

                    Quite impressive. You are actually saying that you do prefer Python
                    over
                    Lisp on a problem of ultra-high level programming which should be
                    the rightful Lisp playhouse ... To be fair, the reason is not lack of
                    power by Lisp, but lack of standardization , still it is something that
                    makes me thinking ...

                    Michele Simionato, Ph. D.
                    MicheleSimionat o@libero.it

                    --- Currently looking for a job ---

                    Comment

                    • Michele Simionato

                      #11
                      Re: For Kenny Tilton: Why do I need macros revisited.

                      mertz@gnosis.cx (David Mertz) wrote in message news:<mailman.1 061594769.30646 .python-list@python.org >...[color=blue]
                      > "Andrew Dalke" <adalke@mindspr ing.com> wrote previously:
                      > |I've seen David Mertz' xml_pickle code which makes good use of
                      > |[metaclasses], but don't yet follow how it works.
                      >
                      > I'm afraid I must insist here that the use of metaclasses in
                      > gnosis.xml.pick le is utterly trivial, and just for show. You'll
                      > have to look elsewhere for "good use" of them :-).
                      >
                      > Yours, David...[/color]

                      For instance Psyco was using metaclasses to wrap the methods to
                      "speed-up", at least when I looked at version 0.4.
                      This was a quite clean usage, simple and effective.
                      When you need to wrap many methods in a class (for instance for
                      logging purposes or other reasons) a metaclass is most probably
                      the best solution you have at your disposal.

                      Michele Simionato, Ph. D.
                      MicheleSimionat o@libero.it

                      --- Currently looking for a job ---

                      Comment

                      • Michele Simionato

                        #12
                        Re: For Kenny Tilton: Why do I need macros revisited.

                        mertz@gnosis.cx (David Mertz) wrote in message news:<mailman.1 061594769.30646 .python-list@python.org >...[color=blue]
                        > "Andrew Dalke" <adalke@mindspr ing.com> wrote previously:
                        > |I've seen David Mertz' xml_pickle code which makes good use of
                        > |[metaclasses], but don't yet follow how it works.
                        >
                        > I'm afraid I must insist here that the use of metaclasses in
                        > gnosis.xml.pick le is utterly trivial, and just for show. You'll
                        > have to look elsewhere for "good use" of them :-).
                        >
                        > Yours, David...[/color]

                        For instance Psyco was using metaclasses to wrap the methods to
                        "speed-up", at least when I looked at version 0.4.
                        This was a quite clean usage, simple and effective.
                        When you need to wrap many methods in a class (for instance for
                        logging purposes or other reasons) a metaclass is most probably
                        the best solution you have at your disposal.

                        Michele Simionato, Ph. D.
                        MicheleSimionat o@libero.it

                        --- Currently looking for a job ---

                        Comment

                        • Paul Foley

                          #13
                          Re: For Kenny Tilton: Why do I need macros revisited.

                          On Fri, 22 Aug 2003 11:10:49 -0400, Terry Reedy wrote:
                          [color=blue][color=green]
                          >> Scheme macros are not the same as Lisp macros. Scheme macros are a
                          >> lot more complicated (and less useful; but most Scheme implementations
                          >> also offer Lisp-style macros...)[/color][/color]
                          [color=blue]
                          > Please excuse my confusing of Scheme with Lisp. I am pleased to find
                          > that my difficulty in reading the Scheme macro stuff wasn't just me.
                          > But note that there have been proposals that if Python were to have a
                          > macro facility, it should be 'hygenic', which I presume means like
                          > Scheme macros.[/color]
                          [color=blue]
                          > Until some advocate of a Python macro facility adds more detail to the
                          > proposal beyound 'Lisp/Scheme-like maco facility', it is really hard
                          > for someone like me, who has used neither, to have much of any
                          > concrete idea of what is being proposed.[/color]

                          I don't know what others are proposing.

                          In Lisp, a macro is really just a function like any other (so people
                          arguing against macros who are not also against functions are clearly
                          insane!). It takes two arguments: a "form" (i.e., some Lisp code) and
                          an "environmen t" (a fairly useless opaque object), and returns more
                          Lisp code. So (a simplified version of) EVAL in a Lisp without macros
                          might look something like

                          (defun eval (form)
                          (typecase form
                          (symbol (symbol-value form))
                          (atom form)
                          (cons (apply (first form) (mapcar #'eval (rest form))))))

                          and to add macros, all that's necessary is

                          (defun macroexpand (form)
                          (if <form is a macro form>
                          (macroexpand (funcall (macro-function (first form)) form <environ>))
                          form))

                          (defun eval (form)
                          (let ((form (macroexpand form)))
                          (typecase form
                          (symbol (symbol-value form))
                          (atom form)
                          (cons (apply (first form) (mapcar #'eval (rest form)))))))


                          If you write a macro, LIST2, such that (LIST2 1 2 3 ...) expands into
                          (LIST (LIST 1) (LIST 2) (LIST 3) ...), and then you use it in a
                          function like

                          (defun foo (list)
                          (let ((x (list2 1 2 3)))
                          ...))

                          in a Lisp-2 (i.e., a language with separate namespaces for variables
                          and functions, so you can have both a variable and a function with the
                          same name at the same time) there's no problem, but in a Lisp-1
                          (single shared namespace, like Scheme and Python) you'd have a big
                          problem: when the list2 macro is expanded, "list" is a variable -- the
                          argument to "foo" -- not the list-constructing function the
                          macro-writer expected.

                          So Scheme introduced the so-called "hygienic" macros [a bad name,
                          implying that non-hygienic macros are "dirty" and to be avoided;
                          "hygienic" macros are the ones I want to avoid!], where names used in
                          the macro expansion are in the scope where the macro was defined,
                          rather than the scope that's in effect where it's expanded, so that
                          "list" in the expansion refers to the list function, not the argument
                          to foo, and bindings made by the macro are not visible to code that
                          comes in from user code.

                          But Scheme macros are not just functions like Lisp macros, either. A
                          Scheme macro is defined as a set of patterns to be matched against
                          the code, and an associated rewrite rule which specifies the code to
                          use instead. [I don't see any reason why these rules need to be
                          written in a Lispy syntax...]

                          --
                          Just because we Lisp programmers are better than everyone else is no
                          excuse for us to be arrogant. -- Erann Gat

                          (setq reply-to
                          (concatenate 'string "Paul Foley " "<mycroft" '(#\@) "actrix.gen.nz> "))

                          Comment

                          • Paul Foley

                            #14
                            Re: For Kenny Tilton: Why do I need macros revisited.

                            On Fri, 22 Aug 2003 11:10:49 -0400, Terry Reedy wrote:
                            [color=blue][color=green]
                            >> Scheme macros are not the same as Lisp macros. Scheme macros are a
                            >> lot more complicated (and less useful; but most Scheme implementations
                            >> also offer Lisp-style macros...)[/color][/color]
                            [color=blue]
                            > Please excuse my confusing of Scheme with Lisp. I am pleased to find
                            > that my difficulty in reading the Scheme macro stuff wasn't just me.
                            > But note that there have been proposals that if Python were to have a
                            > macro facility, it should be 'hygenic', which I presume means like
                            > Scheme macros.[/color]
                            [color=blue]
                            > Until some advocate of a Python macro facility adds more detail to the
                            > proposal beyound 'Lisp/Scheme-like maco facility', it is really hard
                            > for someone like me, who has used neither, to have much of any
                            > concrete idea of what is being proposed.[/color]

                            I don't know what others are proposing.

                            In Lisp, a macro is really just a function like any other (so people
                            arguing against macros who are not also against functions are clearly
                            insane!). It takes two arguments: a "form" (i.e., some Lisp code) and
                            an "environmen t" (a fairly useless opaque object), and returns more
                            Lisp code. So (a simplified version of) EVAL in a Lisp without macros
                            might look something like

                            (defun eval (form)
                            (typecase form
                            (symbol (symbol-value form))
                            (atom form)
                            (cons (apply (first form) (mapcar #'eval (rest form))))))

                            and to add macros, all that's necessary is

                            (defun macroexpand (form)
                            (if <form is a macro form>
                            (macroexpand (funcall (macro-function (first form)) form <environ>))
                            form))

                            (defun eval (form)
                            (let ((form (macroexpand form)))
                            (typecase form
                            (symbol (symbol-value form))
                            (atom form)
                            (cons (apply (first form) (mapcar #'eval (rest form)))))))


                            If you write a macro, LIST2, such that (LIST2 1 2 3 ...) expands into
                            (LIST (LIST 1) (LIST 2) (LIST 3) ...), and then you use it in a
                            function like

                            (defun foo (list)
                            (let ((x (list2 1 2 3)))
                            ...))

                            in a Lisp-2 (i.e., a language with separate namespaces for variables
                            and functions, so you can have both a variable and a function with the
                            same name at the same time) there's no problem, but in a Lisp-1
                            (single shared namespace, like Scheme and Python) you'd have a big
                            problem: when the list2 macro is expanded, "list" is a variable -- the
                            argument to "foo" -- not the list-constructing function the
                            macro-writer expected.

                            So Scheme introduced the so-called "hygienic" macros [a bad name,
                            implying that non-hygienic macros are "dirty" and to be avoided;
                            "hygienic" macros are the ones I want to avoid!], where names used in
                            the macro expansion are in the scope where the macro was defined,
                            rather than the scope that's in effect where it's expanded, so that
                            "list" in the expansion refers to the list function, not the argument
                            to foo, and bindings made by the macro are not visible to code that
                            comes in from user code.

                            But Scheme macros are not just functions like Lisp macros, either. A
                            Scheme macro is defined as a set of patterns to be matched against
                            the code, and an associated rewrite rule which specifies the code to
                            use instead. [I don't see any reason why these rules need to be
                            written in a Lispy syntax...]

                            --
                            Just because we Lisp programmers are better than everyone else is no
                            excuse for us to be arrogant. -- Erann Gat

                            (setq reply-to
                            (concatenate 'string "Paul Foley " "<mycroft" '(#\@) "actrix.gen.nz> "))

                            Comment

                            • David Mertz

                              #15
                              Re: For Kenny Tilton: Why do I need macros revisited.

                              "Andrew Dalke" <adalke@mindspr ing.com> wrote previously:
                              |I've seen David Mertz' xml_pickle code which makes good use of
                              |[metaclasses], but don't yet follow how it works.

                              I'm afraid I must insist here that the use of metaclasses in
                              gnosis.xml.pick le is utterly trivial, and just for show. You'll
                              have to look elsewhere for "good use" of them :-).

                              Yours, David...

                              --
                              mertz@ _/_/_/_/ THIS MESSAGE WAS BROUGHT TO YOU BY: \_\_\_\_ n o
                              gnosis _/_/ Postmodern Enterprises \_\_
                              ..cx _/_/ \_\_ d o
                              _/_/_/ IN A WORLD W/O WALLS, THERE WOULD BE NO GATES \_\_\_ z e


                              Comment

                              Working...