Page 1 of 1

Constant terms in macro parameters...

Posted: Wed Apr 12, 2017 11:50 am
by starfleet
Greetings, this is not homework, but I felt it would be here the best place to post...

I'm trying to program a common-lisp macro (sbcl) to set the syntax for defining a rule in a rule-based system.
My goal is to allow users to specify rules in a syntax like this:

Code: Select all

(defrule  "name of the rule"
    :when   (s-expression 1)
            (s-expression 2)
            ...
            (s-expression n)
    :perform
            (s-expresion 1)
            (s-expression 2)
            ...
            (s-expression m) )
And I face two problems I currently don't know how to solve:

First, is there an intelligent way to include the constant terms (:when and :perform) without adding them as specific parameters to the macro?

Second, How do I accept two chunks of unknown number of s-expressions without forcing the user to delimit all the lhs and rhs expressions in a list?

Although I have reviewed many codes with rule-based systems (CL-mycyn, Leibniz, Lisa, etc) the only problem seems to be my inexperience with macros and CL in general...
Any help will be greatly appreciated...

Thanks in advance...

Re: Constant terms in macro parameters...

Posted: Wed Apr 12, 2017 5:44 pm
by sylwester

Code: Select all

(defmacro defrule (name &rest rest)
  ...)
Now name will be "name of the rule" and rest will be (:when (s-expression 1) ... :perform (s-expresion 1) ...)
Your macro can iterate and collect and do all sorts of things and you look for :when and :perform to switch mode.

Re: Constant terms in macro parameters...

Posted: Sat Apr 15, 2017 11:59 am
by David Mullen
Seems like it might be easiest—if not the right thing in your case—to just look for any keywords to delimit the associated expressions, rather than specific keywords. Sticking them in a property list makes the rule definition a bit more tractable:

Code: Select all

(defun rule-definition-plist (body)
  (loop with plist for (keyword . tail) = body
        until (endp body) finally (return plist)
        do (check-type keyword keyword)
           (setq body (member-if #'keywordp tail))
           (let ((key-expressions (ldiff tail body)))
             (setf (getf plist keyword) key-expressions))))
Of course, the plist will tend to be in the reverse order:

Code: Select all

? (rule-definition-plist
   '(:when   (when-expression 1)
             (when-expression 2)
     :perform
             (perform-expression 1)
             (perform-expression 2)))
(:PERFORM ((PERFORM-EXPRESSION 1) (PERFORM-EXPRESSION 2))
 :WHEN ((WHEN-EXPRESSION 1) (WHEN-EXPRESSION 2)))