compare to nil in clips - expert-system

How do I compare to nil in clips ?
I have tried
(defrule update-time
?cur-time <- (current-time ?time)
(order (event-time ?new-time-o&:(neq ?new-time-o nil)))
I have also tried
(neq ?new-time-o "nil")
none of it seems to work, I get no activation.

You haven't provided enough information to answer your question. Given the appropriate data, this rule will activate:
CLIPS> (deftemplate order (slot event-time))
CLIPS>
(defrule update-time
?cur-time <- (current-time ?time)
(order (event-time ?new-time-o&:(neq ?new-time-o nil)))
=>)
CLIPS> (assert (order (event-time (time))))
<Fact-1>
CLIPS> (assert (current-time (time)))
<Fact-2>
CLIPS> (agenda)
0 update-time: f-2,f-1
For a total of 1 activation.
CLIPS>

Related

Understanding variable scope in given code

I'm a beginner in Emacs lisp, so this is really a noob question. Let's say that I have to write a function that uses a loop to add 1 to each element of a numeric vector.
Here is the code I wrote (the comments indicate what I'm trying to do at each step):
(defun add-one (x)
"Use a loop to add 1 to each element of list X"
(let* ((res x) ; make a copy of X
(counter 0)) ; set counter to 0
(while (< counter (length x))
;; Replace each element of RES by adding 1:
(setcar (nthcdr counter res) (1+ (car (nthcdr counter x))))
(setq counter (1+ counter)))
;; Display result:
(message "%s" res)))
But my code seems to be destructive for x, since several calls to the function do not produce the same result:
;; Define a list:
(setq mylist '(1 2 3 4))
;; Several calls to the function:
(add-one mylist) ; -> (2 3 4 5)
(add-one mylist) ; -> (3 4 5 6)
Here is my question: I don't understand why my code is destructive (I expected the result to be (2 3 4 5) at each execution). I know that setcar is destructive, but it is applied to a copy of x, not to x itself. So why is the result changing?
Thanks!
For the sake of clarity:
Despite the fact you do not copy input list, your code is not at all lispy. Try this instead:
(mapcar '1+ '(1 2 3 4))
Let does not make a copy of anything, so this assigns the value referenced by the variable x to the variable res. Hence any changes to the list referenced by res also change the list referenced by x
(let* ((res x) ; make a copy of X

Logic for multivalued search (contains)

I need to construct some logic according to the above table - where S1, S2 ,S3 are strings and I need to find if the field values (strings) CONTAIN these strings.
Green rows should be returned, red rows not. The list of red and green rows is not exhaustive, but enough that you get the idea.
I feel I am missing a really simple way to do this - any ideas?
((Field1 == S1) || (Field1 == S2) || (Field1 == S3)) && ((Field2 == S1) || (Field2 == S2) || (Field2 == S3)) && ((Field3 == S1) || (Field3 == S2) || (Field3 == S3)) Should be the condition to check this.

Intersection-sets using iterator in Scheme

I am trying to create a function that takes two set objects and returns a new set object that is the intersection of those two objects while using an iterator.
Here are some functions that I used, basic-set1 and basic-set2 are set objects that are initially empty.
((basic-set1 'get-set))
>(d c b a)
((basic-set2 'get-set))
>(a b)
(define my-iterator3 basic-set1)
((my-iterator3 'next))
> d
((my-iterator3 'next))
> c
((my-iterator3 'hasnext))
> #t
My desired output
(intersection-sets basic-set1 basic-set2)
> (b a)
This is the code I have so far.
(define (intersect-sets set1 set2)
(define my-iterator3 ((set1 'get-iterator )))
(define result (basic-set))
(define (iter)
(let ((x ((my-iterator3 'next))))
(cond ((not ((my-iterator3 'hasnext))) result)
(((set2 'element?) x)
(begin ((result 'insert) x)
(iter)))
(else
(iter)))))
(iter))
Tested output:
(intersect-sets basic-set1 basic-set2)
>#<procedure:...Problem3.rkt:60:2
I'm kind of stumped. Any help would be appreciated.
As far as I can tell your code is correct. The first cond clause returns result, which is a procedure. If you want the set returned as a list try ((not ((my-iterator3 'hasnext))) ((result 'get-set))) as your first cond clause in iter

What is the core difference between strings and numbers in Common Lisp?

Being new with CL, I play a lot with simple algorithms. For instance, I tried to implement a function for removing all unique elements in a list.
(1 2 2 3 3 4 5 3) -> (2 2 3 3 3)
First attempt lead to this code:
(defun remove-unique (items)
(let ((duplicates (set-difference items (remove-duplicates items :test #'equal))))
(append duplicates (remove-duplicates duplicates :test #'equal))))
This works ok with strings but does always return NIL for numbers. Reading a bit more about set-difference I've learned that it isn't suppose to work with duplicate populated lists at all, it just works somehow in my case, so I abandoned the approach as unportable and moved along.
Another attempt is:
(defun remove-unique (items)
(loop for item in items
when (member item (cdr (member item items)))
collect item))
And this works ok with numbers, but returns NIL for strings.
Apparently there is a core difference between strings and numbers I don't understand. How come list processing functions such as member and set-difference work differently on them?
The equality comparison for numbers, characters and strings is indeed different. Equal, which you should be wary to use because it is more expensive, does structure equality (so it descends on some objects). eq does object equality. And eql does object equality for most cases except for numbers (where they check type and value) and characters (where they check 'value')
See the hyperspec entries for equal, eql and eq for more information.
Strings are more related to lists than numbers since both lists and strings are sequences.
"Hello" is a sequence (compund data type) starting with the primitive character value #\H and ending with #\o.
'(1 2 3) is a sequence (compond data type) starting with the primitive numeric value 1 and ending with 3.
Characters are similar to numbers in that they are primitive values. Primitive values can be compared using eql while sequences, that are not the same object, can be compared using equal
(setq list1 (list 1 2 3))
(setq list2 (list 1 2 3))
(eql list1 list2)
;==> NIL
(equal list1 list2)
;==> T
;; comparing first element of both lists using eql
(eql (car list1) (car list2))
;==> T
(setq string1 "Hello")
(setq string2 "Hello")
(eql string1 string2)
;==> NIL
(equal string1 string2)
;==> T
;; comparing first character of both strings using eql
(eql (elt string1 0) (elt string2 0))
;==> T
Most (if not all) functions in Common Lisp that compares something usually has an optional named argument :test where you can supply how elements compare. the default usually is eql. To make them behave corretly with sequences you need to supply #'equal as :test.
(defun remove-unique (items &key (test 'eql))
(loop
:with table := (make-hash-table :test test)
:for element :in items :do
(setf (gethash element table)
(1+ (gethash element table 0)))
:finally
(return
(loop
:for k :being :the :hash-keys :of table
:using (:hash-value v)
:when (> v 1) :nconc (make-list v :initial-element k)))))
(defun remove-unique (items &key (test 'eql))
(loop
:with table := (make-hash-table :test test)
:for element :in items :do
(setf (gethash element table)
(1+ (gethash element table 0)))
:finally
(return
(loop
:for element :in items
:unless (= 1 (gethash element table))
:collect element))))
I'd probably use the first variant because it makes less reads from hash-table, but you'd need to check that items in the list aren't modified later in place.
(remove-unique '("1" "2" "2" "3" "3" "4" "5" "3") :test #'equal)
gives:
("2" "2" "3" "3" "3")
but
(remove-unique '("1" "2" "2" "3" "3" "4" "5" "3"))
gives:
NIL

CLIPS subset duplicate values

I want to have a rule that suggests the possible item combinations in a player's inventory.
Below are some example facts. Item facts contain the recipe for item combinations and the player facts contain the items in the player's inventory.
(player (name x) (inventory "aaa" "bbb" "ccc"))
(item (name xxx) (recipe "aaa" "bbb"))
(item (name yyy) (recipe "aaa" "aaa" "ccc"))
Below is the rule I have written:
; ; Item Combination rule
(defrule item-combination
(player (name ?n1) (inventory $?i1))
(item (name ?n2) (recipe $?i2))
(test (subsetp $?i2 $?i1))
=>
(assert (can-combine ?n1 ?n2))
)
The rule works well if there are no duplicate items in the recipe.
For example, for item yyy, we need 2 instances of "aaa", however (subsetp (aaa aaa ccc) (aaa bbb ccc)) will return true. However, I require that there contain 2 instances of "aaa" in the player's inventory.
I wonder if there is a function to check subset that involves duplicate values.
EDIT: I have written my own function
(deffunction subsetdp (?sub ?set)
(if (eq 0 (length$ ?sub))
then (return TRUE))
(bind ?x (member$ (nth$ 1 ?sub) ?set))
(if ?x
then (return (subsetdp (rest$ ?sub) (delete$ ?set ?x ?x))))
FALSE)
)
You'll need to write your own function as you have done if you want to check for duplicates.

Resources