From: David E. Young
Subject: Macros and keyword arguments
Date: 
Message-ID: <3ADC6B46.D411DD2D@nc.rr.com>
Greetings. Most likely I'm being obtuse here, but I seem unable to
figure out how to do the following without some "manual" parsing.

I would like to write a macro that 1) accepts keyword arguments; and 2)
sends the BODY parameter on for further processing. In other words,
something like:

(defmacro defrule (...) ...)

should handle both

(defrule rocky :salience 10
  (rocky)
   =>
   (do-something))

and

(defrule boris
   (some-fact)
    ...)

I've started with this:

(defmacro defrule (name &rest body)
  `(apply #'parse-defrule ',name ',body))

(defun parse-defrule (name &rest args &key (salience 0)) ...)

but this is obviously incorrect. Note that I already have a functioning
DEFRULE macro; I'm simply trying to extend it to support keyword
arguments (if I can).

Thanks and regards,

--
-----------------------------------------------------------------
David E. Young
Fujitsu Network Communications  (defun real-language? (lang)
(········@computer.org)           (eq lang 'LISP))

"But all the world understands my language."
  -- Franz Joseph Haydn (1732-1809)

From: Barry Margolin
Subject: Re: Macros and keyword arguments
Date: 
Message-ID: <Zn_C6.1$IL1.263@burlma1-snr2>
In article <·················@nc.rr.com>,
David E. Young <·······@nc.rr.com> wrote:
>Greetings. Most likely I'm being obtuse here, but I seem unable to
>figure out how to do the following without some "manual" parsing.
>
>I would like to write a macro that 1) accepts keyword arguments; and 2)
>sends the BODY parameter on for further processing. In other words,
>something like:
>
>(defmacro defrule (...) ...)
>
>should handle both
>
>(defrule rocky :salience 10
>  (rocky)
>   =>
>   (do-something))
>
>and
>
>(defrule boris
>   (some-fact)
>    ...)
>
>I've started with this:
>
>(defmacro defrule (name &rest body)
>  `(apply #'parse-defrule ',name ',body))
>
>(defun parse-defrule (name &rest args &key (salience 0)) ...)
>
>but this is obviously incorrect. Note that I already have a functioning
>DEFRULE macro; I'm simply trying to extend it to support keyword
>arguments (if I can).

The basic problem with your approach is that the built-in keyword argument
parser expects keyword/argument pairs to be the remainder of the
arguments.  It can't deal with keywords followed by a body, which seems to
be what you're trying to do.

A common way to design macros like this is to have a required subform
containing all the keywords.

(defmacro defrule (rule-name (&key salience ...) &body body) ...)

This would allow you to write:

(defrule rocky (:salience 10)
  (rocky) => (do-something))

(defrule boris ()
  (some-fact)
  ...)

If you don't like that empty list, you can do it like DEFSTRUCT:

(defmacro defrule (name-and-options &body body)
  (destructuring-bind (name &key salience ...)
      (if (listp name-and-options)
          name-and-options
          (list name-and-options))
    ...))

Then you can write:

(defrule (rocky :salience 10)
  (rocky) => (do-something))

(defrule boris
  (some-fact)
  ...)

-- 
Barry Margolin, ······@genuity.net
Genuity, Burlington, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
From: David E. Young
Subject: Re: Macros and keyword arguments
Date: 
Message-ID: <3ADC742D.267391AB@nc.rr.com>
Barry Margolin wrote:

> A common way to design macros like this is to have a required subform
> containing all the keywords...

Yes, of course. Either of your suggestions would be fine; thanks very much.

Regards,

--
-----------------------------------------------------------------
David E. Young
Fujitsu Network Communications  (defun real-language? (lang)
(········@computer.org)           (eq lang 'LISP))

"But all the world understands my language."
  -- Franz Joseph Haydn (1732-1809)
From: Hallvard B Furuseth
Subject: Re: Macros and keyword arguments
Date: 
Message-ID: <HBF.20010417ozca@bombur.uio.no>
Barry Margolin <······@genuity.net> writes:

> [the built-in keyword argument parser] can't deal with keywords
> followed by a body, which seems to be what you're trying to do.

I've wondered about that.  Why isn't &rest allowed _after_ &key (as well
as before it), so &key could eat any matching keyword arguments before
giving the remainder to the following &rest?

-- 
Hallvard
From: Barry Margolin
Subject: Re: Macros and keyword arguments
Date: 
Message-ID: <7d1D6.8$IL1.526@burlma1-snr2>
In article <················@bombur.uio.no>,
Hallvard B Furuseth  <············@usit.uio.no> wrote:
>Barry Margolin <······@genuity.net> writes:
>
>> [the built-in keyword argument parser] can't deal with keywords
>> followed by a body, which seems to be what you're trying to do.
>
>I've wondered about that.  Why isn't &rest allowed _after_ &key (as well
>as before it), so &key could eat any matching keyword arguments before
>giving the remainder to the following &rest?

How is it supposed to know when to stop gobbling keyword arguments?  How
can it tell the difference between a rest-list that just happens to begin
with a keyword?  And what about the fact that we don't even require
keywords to be in the keyword package, so any symbol could be a keyword?

What you're probably thinking of is something like Unix's command-line
conventions, where options all start with '-', and the first non-option
ends option processing.  But that style has problems if you want to provide
a non-option that just happens to begin with a '-'.  Eventually they came
up with the convention of using '--' to explicitly end the option part,
forcing everything after it to be a normal argument.  We would need
something similar, e.g.

(defrule rocky :salience 10 :body ...)

where :body is a special keyword that indicates that keyword processing
should stop and the rest is the body.  Ugh.  While it certainly would be
feasible, normal list structure provides all the support for reasonable
parsing that we really need.

-- 
Barry Margolin, ······@genuity.net
Genuity, Burlington, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
From: Kent M Pitman
Subject: Re: Macros and keyword arguments
Date: 
Message-ID: <sfwlmozpii6.fsf@world.std.com>
"David E. Young" <·······@nc.rr.com> writes:

> I would like to write a macro that 1) accepts keyword arguments; and 2)
> sends the BODY parameter on for further processing.

You can't get there from here.  The normal way to win is:

 (defmacro defrule (name (&key salience) &body forms) ...)

This means you'd write:
 
 (defrule rocky (:salience 10)
   (rocky)
   =>
   (do-something))

 (defrule boris ()
   (some-fact)
   ...)


Note the extra ()'s around :salience 10 in the first example, and the
extra () after boris in the second.

To do the exact syntax you say you want requires some special processing.
e.g.,

 (defmacro defrule (name &rest body)
   (let ((keys '()))
     (loop
       (unless (keywordp (car body)) (return))
       (push (pop body) keys)  ;keyword
       (push (pop body) keys)) ;value
     (setq keys (nreverse keys))
     `(defrule-1 ,name ,keys ,@body)))

where defrule-1 is defined as the first example above:

 (defmacro defrule-1 (name (&key salience) &body forms) ...)

> Note that I already have a functioning
> DEFRULE macro; I'm simply trying to extend it to support keyword
> arguments (if I can).

Hope this is enough to help you get there...
From: Sashank Varma
Subject: Re: Macros and keyword arguments
Date: 
Message-ID: <sashank.varma-1704012212190001@129.59.212.53>
In article <·················@nc.rr.com>, ·······@nc.rr.com wrote:
[snip]
>I would like to write a macro that 1) accepts keyword arguments; and 2)
>sends the BODY parameter on for further processing. In other words,
>something like:
>
>(defmacro defrule (...) ...)
>
>should handle both
>
>(defrule rocky :salience 10
>  (rocky)
>   =>
>   (do-something))
>
>and
>
>(defrule boris
>   (some-fact)
>    ...)
[snip]

In article <···············@world.std.com>, Kent M Pitman
<······@world.std.com> wrote:
[snip]
>You can't get there from here.  The normal way to win is:
>
> (defmacro defrule (name (&key salience) &body forms) ...)
>
>This means you'd write:
> 
> (defrule rocky (:salience 10)
>   (rocky)
>   =>
>   (do-something))
>
> (defrule boris ()
>   (some-fact)
>   ...)
>
>
>Note the extra ()'s around :salience 10 in the first example, and the
>extra () after boris in the second.
[snip]

it seems ugly to have to include an empty () in rule definitions that
don't supply keyword arguments.  what proportion of rules do you expect
to be of this form?  if it's close to one, you could provide two rule
definition commands, one for vanilla rules unadorned with keywords and
one for verbose definitions, i.e.,

(defrule+ rocky (:salience 10)
  (rocky)
  =>
  (do-something))

(defrule boris
  (some-fact)
  ...)

(i'm sure there's a better naming convention than appending a '+'.)

or you could have keywords optionally appear at the end of the rule
definition, paralleling the location of :default-initargs in defclass:

(defrule rocky
  (rocky)
  =>
  (do-something)
  &options
   :salience 10)

(defrule boris
  (some-fact)
  =>
  (some-action))

(once again, i'm sure you can think of a better separator than
'&options'.)

of course, this second second format requires manual parsing.  i
suggest these alternate formats because the possibility that most
rules will have empty keyword argument lists disturbs my aesthetic
sense.

sashank
From: Rahul Jain
Subject: Re: Macros and keyword arguments
Date: 
Message-ID: <9bjjq0$ep4$1@joe.rice.edu>
In article <······························@129.59.212.53> on Tue, 17 Apr
2001 22:12:19 -0500, "Sashank Varma" <·············@vanderbilt.edu> wrote:

> of course, this second second format requires manual parsing.  i suggest
> these alternate formats because the possibility that most rules will
> have empty keyword argument lists disturbs my aesthetic sense.

I don't really see the problem with this situation, since it parallels
the syntax of defun/defmethod/etc exactly. If that's not acceptable,
Barry already showed an alternative syntax (a bit like scheme's define).
Both of those syntaxes seems reasonable to me, without any extra markers.
Of course, this is a question of aesthetics, but I like the way that the
form with the empty list parallels how lambda lists are defined in other
forms in the lanugage.

-- 
-> -/-                       - Rahul Jain -                       -\- <-
-> -\- http://linux.rice.edu/~rahul -=- ·················@usa.net -/- <-
-> -/- "I never could get the hang of Thursdays." - HHGTTG by DNA -\- <-
|--|--------|--------------|----|-------------|------|---------|-----|-|
   Version 11.423.999.220020101.23.50110101.042
   (c)1996-2000, All rights reserved. Disclaimer available upon request.
From: Sashank Varma
Subject: Re: Macros and keyword arguments
Date: 
Message-ID: <sashank.varma-1804010934540001@129.59.212.53>
In article <············@joe.rice.edu>, "Rahul Jain" <·····@rice.edu> wrote:

>I don't really see the problem with this situation, since it parallels
>the syntax of defun/defmethod/etc exactly. If that's not acceptable,
>Barry already showed an alternative syntax (a bit like scheme's define).
>Both of those syntaxes seems reasonable to me, without any extra markers.
>Of course, this is a question of aesthetics, but I like the way that the
>form with the empty list parallels how lambda lists are defined in other
>forms in the lanugage.

except that, as i understand it (from his sourceforge site), david's goal
is not to make a lisp-like expert system shell, but to clone an existing
shell -- clips (written in c) or jess (written in java).  from this
perspective, the question is what syntax makes the most sense to someone
writing rules in david's language without regard to the underlying
implementation language.

sashank
From: David E. Young
Subject: Re: Macros and keyword arguments
Date: 
Message-ID: <3ADEE728.223ED140@nc.rr.com>
Sashank Varma wrote:

> except that, as i understand it (from his sourceforge site), david's goal
> is not to make a lisp-like expert system shell, but to clone an existing
> shell -- clips (written in c) or jess (written in java)...

Actually, LISA is influenced by CLIPS and JESS but not limited by them. Thus,
using a syntax that is "lisp-like" in some respect doesn't violate any
particular project goal. LISA should strive to be familiar to folks with a
background in those systems, but also feel "comfortable" to Lisp developers.
Whether I can do both remains to be seen.

I appreciate the input from everyone.

Regards,

--
-----------------------------------------------------------------
David E. Young
Fujitsu Network Communications  (defun real-language? (lang)
(········@computer.org)           (eq lang 'LISP))

"But all the world understands my language."
  -- Franz Joseph Haydn (1732-1809)