2007-10-22

Another Clips and Lisa comparison

I spent this evening with Emacs, CLisp and Lisa. I wanted to get this piece of Clips code working:

|CLIPS> (deftemplate movie
| (multislot title))
|CLIPS> (deffacts movies
| (movie (title "A" "B" "C"))
| (movie (title "B" "C" "D"))
| (movie (title "C" "D" "E")))
|CLIPS> (defrule chain
| ?m1 <- (movie (title $? $?link&:(> (length$ $?link) 0)))
| ?m2 <- (movie (title $?link $?))
| (test (neq ?m2 ?m1)) ; Avoid infinite chains because of
| ; movie titles like "Liar Liar".
| =>
| (printout t (fact-slot-value ?m1 title) " " (fact-slot-value ?m2 title) crlf))
|CLIPS> (reset)
|==> Activation 0 chain: f-1,f-2
|==> Activation 0 chain: f-2,f-3
|==> Activation 0 chain: f-1,f-3
|CLIPS> (run)
|("A" "B" "C") ("C" "D" "E")
|("B" "C" "D") ("C" "D" "E")
|("A" "B" "C") ("B" "C" "D")
Note how elegantly $?link matches any number of elements in a multislot.

Unfortunately, there are no multislots in Lisa. But, you're allowed to add a list (or even a list of lists) to a slot. Only thing is that you either have to match it as-is or provide your own predicate function to perform whatever test you need done. Here's what I came up with:
|LISA-USER> (deftemplate movie ()
| (slot title))
|#[STANDARD-CLASS MOVIE]
|LISA-USER> (deffacts movies ()
| (movie (title '("A" "B" "C")))
| (movie (title '("B" "C" "D")))
| (movie (title '("C" "D" "E"))))
|(#[DEFFACTS
| MOVIES ; (#[MOVIE ; id -1 #x19FF2789] #[MOVIE ; id -1 #x19FF2ADD]
| #[MOVIE ; id -1 #x19FF2E31])
| #x19FF2EDD])
|LISA-USER> (defun overlap? (list-1 list-2)
| (if (not (equal list-1 list-2))
| (dotimes (index (min (length list-1)
| (length list-2)))
| (if (equal (subseq list-1 (- (length list-1) index 1) (length list-1))
| (subseq list-2 0 (+ index 1)))
| (return-from overlap? t))))
| nil)
|OVERLAP?
|LISA-USER> (defrule chain ()
| (?m1 (movie (title ?title1)))
| (?m2 (movie (title ?title2)))
| (test (overlap? ?title1 ?title2))
| =>
| (format t "~A ~A~%" ?title1 ?title2))
|#[RULE CHAIN]
|LISA-USER> (reset)
|T
|LISA-USER> (run)
|(A B C) (B C D)
|(B C D) (C D E)
|(A B C) (C D E)
|3
Not quite as elegant... but it works. I never managed to get the not equal test working in the rule so I had to place it in the overlap? function. Other than that, I think they're about as equivalent as they can get.

Inga kommentarer: