Lisp packages are giving me fits -- here's the problem. I need help!
I'm trying to write a generic expert system shell that can input rules
and facts, and output a new set of facts. I want to use CLIPS syntax,
so the rules look like:
(defrule rule-name
"doc string"
(condition 1)
(condition 2)
=>
(new-fact) )
My code works fine if I throw everything I'm using into one package.
But I want to have the generic expert shell in a separate package,
and call it from other packages. The problem is the '=>' token. It
keeps getting qualified with the calling package name (like
caller::=>), so in the expert system package, my equal test for =>
doesn't work (when I try to parse the incoming rule.)
I've tried various combinations of import/export/shadow between
the packages, but nothing seems to work. All I want to do is have
the => symbol shared between packages.
Can someone enlighten me? Thanks!
Alex
In article <··········@blackbird.afit.af.mil> ········@afit.af.mil (Alex Kilpatrick) writes:
> Lisp packages are giving me fits -- here's the problem. I need help!
>
> I'm trying to write a generic expert system shell that can input rules
> and facts, and output a new set of facts. I want to use CLIPS syntax,
> so the rules look like:
>
> (defrule rule-name
> "doc string"
> (condition 1)
> (condition 2)
> =>
> (new-fact) )
>
> My code works fine if I throw everything I'm using into one package.
> But I want to have the generic expert shell in a separate package,
> and call it from other packages. The problem is the '=>' token. It
> keeps getting qualified with the calling package name (like
> caller::=>), so in the expert system package, my equal test for =>
> doesn't work (when I try to parse the incoming rule.)
>
> I've tried various combinations of import/export/shadow between
> the packages, but nothing seems to work. All I want to do is have
> the => symbol shared between packages.
>
> Can someone enlighten me? Thanks!
>
> Alex
>
Here are a couple of possibilities:
(1) Use the keyword package. That means your syntax token has to be :=>, which
is ugly but not too horrible.
(defrule rule-name
"doc string"
(condition 1)
(condition 2)
:=>
(new-fact) )
(2) Put the token in the Common Lisp package, where everyone will inherit it.
(export 'common-lisp::=> :common-lisp)
Some implementations won't let you put things in the Common Lisp package, and
it's a little unportable for that reason.
Secondly, the Common Lisp package really ought to be pristine, so this isn't a
great idea, but it might be okay if you're willing to take the risk. The risk
is that you load your system and two other systems, each of which are nicely
defined in their own packages and each defines the => symbol. Now, the two
systems conflict because they are defining the *same* => symbol and they didn't
think to shadow it because they shouldn't have had to. We actually ran into
this problem in our lab because the Lisp implementation erroneously had the
symbol "variable" in the CL package.
(3) Use STRING-EQUAL instead of EQL in your macro:
(defmacro defrule (name doc-string &rest stuff)
(let ((i (position "=>" stuff :test
#'(lambda (x y)
(and (atom x) (atom y) (string-equal x y))))))
(let ((antecedents (subseq stuff 0 i))
(consequents (subseq stuff (1+ i))))
...)))
Then you don't need to worry about the package of your syntax token. I like
this solution best.
I hope this helps.
Scott D. Anderson
········@cs.umass.edu
In article <······················@earhart.cs.umass.edu>, ········@earhart.cs.umass.edu (Scott D. Anderson) writes:
>
> (3) Use STRING-EQUAL instead of EQL in your macro:
>
> (defmacro defrule (name doc-string &rest stuff)
> (let ((i (position "=>" stuff :test
> #'(lambda (x y)
> (and (atom x) (atom y) (string-equal x y))))))
> (let ((antecedents (subseq stuff 0 i))
> (consequents (subseq stuff (1+ i))))
> ...)))
>
> Then you don't need to worry about the package of your syntax token. I like
> this solution best.
Absolutely the right way to go.
Minor fix -- the above will blow up if a number appears in the
rule before the =>. Use SYMBOLP instead of ATOM.
Even better in my opinion is to define a NAME-EQUAL predicate once and
for all:
(defun name-equal (x y)
(or (eql x y)
(and (symbolp x) (symbolp y) (string= x y))))
then just say (POSITION '=> STUFF :TEST #'NAME-EQUAL)