I have written the following Jess rule to use it in a Protege ontology.
(mapclass Cliente)
(defrule perfil-familia-numerosa
?cliente <- (object (is-a Cliente)
(nombre ?name)
(discapacidad? ?discapacity)
(distrito_deseado ?desired_district)
(n_miembros_familia ?n)
(presupuesto_maximo ?max)
(presupuesto_minimo ?min))
(test (> n 4))
=>
(assert (perfil-cliente ?name soltero)))
When I try entering it in the Jess tab, I get a type error Jess reported an error in routine > [...] java.lang.Integer cannot be cast to java.lang.String.
However, the slot in question is an Integer, so it is not clear to me why Jess it's treating it as a String. Any help?
The problem is here:
(test (> n 4))
A reference to a bound variable retains the '?', so you have to write
(test (> ?n 4))
However, it might be better to add this constraint to (n_miembros_familia ?n).
(n_miembros_familia ?n&:(> ?n 4))
Related
I don't understand why this binding expression is being interpreted fine on dialog but not inside a defrule:
CLIPS> (bind ?test (nth$ 1 (create$ 1)))
1
New window:
(defrule testrule
(bind ?test2 (nth$ 1 (create$ 1)))
=>
(assert (nothing here)))
Output after the untitled window's "Load Buffer":
CLIPS> Loading Selection...
Defining defrule: testrule
[PRNTUTIL2] Syntax Error: Check appropriate syntax for defrule.
ERROR:
(defrule MAIN::testrule
(bind ?test2 (
CLIPS>
How can it even fail being the same on both cases?
I have tested this problem several times, so to clarify it isn't problem from rest of defrule syntax, which you can verify by looking the defrule parsing cuts on the binding line.
Thanks.
It's a problem with your defrule syntax. You use the test conditional element to evaluate an expression in the conditions of a rule. The syntax you've used indicates that you're attempting to match a fact with the relation name bind. The analog to what you're doing at the command line is to execute the function call to bind from the actions of the rule:
CLIPS> (bind ?test (nth$ 1 (create$ 1)))
1
CLIPS>
(defrule testrule
=>
(bind ?test (nth$ 1 (create$ 1)))
(printout t ?test crlf))
CLIPS> (run)
1
CLIPS>
Because parentheses are extensively used as delimiters in CLIPS, there are many cases where context determines the meaning of a piece of code. For example, here's a call to the printout command from the command prompt:
CLIPS> (printout t Hello crlf)
Hello
CLIPS>
Here's a similar call from the actions of a rule:
CLIPS>
(defrule hello
=>
(printout t Hello crlf))
CLIPS> (run)
Hello
CLIPS>
Moving the printout code to the conditions of the rule changes the meaning of the code from a function call to a pattern intended to match a fact:
CLIPS>
(defrule hello
(printout t Hello crlf)
=>)
CLIPS> (agenda)
CLIPS> (facts)
f-0 (initial-fact)
For a total of 1 fact.
CLIPS> (assert (printout t Hello crlf))
<Fact-1>
CLIPS> (agenda)
0 hello: f-1
For a total of 1 activation.
CLIPS> (facts)
f-0 (initial-fact)
f-1 (printout t Hello crlf)
For a total of 2 facts.
CLIPS>
The test conditional element can be used in the conditions of a rule to indicate that the enclosed code is a function call and not a pattern matching a fact:
CLIPS>
(defrule hello (test (printout t Hello crlf)) =>)
Hello
CLIPS>
Some rule-based languages allow you to bind a variable to a derived value in the conditions of a rule, however, CLIPS does not support this, so can't get around this limitation by placing the bind functional call within a test conditional element:
CLIPS> (defrule hello (test (bind ?x 1)) => (printout t ?x crlf))
[PRCCODE3] Undefined variable x referenced in RHS of defrule.
ERROR:
(defrule MAIN::hello
(test (bind ?x 1))
=>
(printout t ?x crlf))
CLIPS>
I am still very beginner in LISP and hope that you all could give me some suggestions on how to solve the following problem.
(CG-USER(1):defstruct Test()
(TestValue 10)
(TestChild 'none)
)
TEST
CG-USER(2): (defun testvalue(item)
(slot-value item 'TESTCHILD))
TESTVALUE
CG-USER(3):(setf TestObject(make-Test :TestChild '(TestObject2 B C)))
#S(TEST :NIL NIL :TESTVALUE 10 :TESTCHILD (TESTOBJECT2 B C))
CG-USER(4): (setf TestObject2(make-Test :TestChild '(D E F)))
#S(TEST :NIL NIL :TESTVALUE 10 :TESTCHILD (D E F))
CG-USER(5): (setf aaa (car (testvalue TestObject)))
TESTOBJECT2
CG-USER(6): (testvalue aaa)
Error: The slot TESTCHILD is missing from the object TESTOBJECT2 of class #<BUILT-IN-CLASS SYMBOL> during
operation SLOT-VALUE
[condition type: PROGRAM-ERROR]
The following is my code. As you can see, I am trying to read the details in the object TestObject2 through the function testvalue . My main purpose is to able to determine the name of the object (TestObject2) from the another object first (in this case, TestObject) as I do not know the name of the name TestObject2 yet.
But however, once I managed to successfully retrieve the name TestObject2 , when I try to access the elements inside the object (TestObject2) , it no longer identify the variable holding TestObject2 (in this case, "aaa") as an object. Thus, it could not read the testvalue of it, resulting in the error.
I am very beginner at LISP and I could not figure out on how to solve this. It would be really great if anyone could provide a sample solution for this. Thanks.
P/S: Also, may I ask what is the NIL NIL in this line? And any way to remove it?
#S(TEST :NIL NIL :TESTVALUE 10 :TESTCHILD (D E F))
Second question:
(defstruct Test()
(TestValue 10)
(TestChild 'none))
Let's format above slightly different:
(defstruct Test ; the structure has a name `TEST`
() ; the first slot is named `NIL`
(TestValue 10) ; the second slot is named `TESTVALUE`
(TestChild 'none)) ; the third slot is named `TESTCHILD`
So, it makes sense to remove the first slot... ;-) and we get:
(defstruct Test ; the structure has a name `TEST`
(TestValue 10) ; the first slot is named `TESTVALUE`
(TestChild 'none)) ; the second slot is named `TESTCHILD`
First question:
TESTOBJECT2 is a symbol. If the symbol has a value, you can retrieve it with the function SYMBOL-VALUE.
(symbol-value 'testobject2)
Generally you want to slim your code a bit:
CL-USER 42 > (defstruct test
(value 10)
(child 'none))
TEST
In above we don't need the test prefix. DEFSTRUCT already creates accessors with TEST- as the prefix.
CL-USER 43 > (setf test-object (make-test :child '(test-object2 b c)))
#S(TEST :VALUE 10 :CHILD (TEST-OBJECT2 B C))
Note that in your example and in above code, the :child is not a structure. It is just a list of three symbols.
CL-USER 44 > (setf test-object2 (make-test :child '(d e f)))
#S(TEST :VALUE 10 :CHILD (D E F))
Again, the child of above is a list of three symbols.
CL-USER 45 > (setf aaa (car (test-child test-object)))
TEST-OBJECT2
Above: The first of that list is the symbol TEST-OBJECT2.
CL-USER 46 > (test-value (symbol-value aaa))
10
Above: we can retrieve the symbol value of the symbol TEST-OBJECT2, which is the value of the variable AAA.
I am using the [family ontology][1] to test Jess rules. Everything works fine unless manipulating data with Jess built-in functions e.g. min and max. I have designed the following rule:
(defrule print_people_min_age
(object (https://wiki.csc.calpoly.edu/OntologyTutorial/family_example.owl#age ?a))
=>
(printout t "Min age " (min ?a) crlf))
The rule compiles well, but I am not getting the desired output. It outputs me ages of each person in the ontology. I tried to put the min function in the LHS but it results in error.
[1]: Family Ontology https://wiki.csc.calpoly.edu/OntologyTutorial/attachment/wiki/AddingRuleWithJessTab/family_example_for_rules.owl
Functions (min <numeric-expresion>+) and (max <numeric-expresion>+) are meant to be applied to a number of arguments - you are calling it with just one argument. The rule fires once for each object, and the minimum of that single age is - that age.
This rule illustrates how to find a minimum:
(defrule print_people_min_age
(object (https://wiki.csc.calpoly.edu/OntologyTutorial/family_example.owl#age ?a1))
(not (object (https://wiki.csc.calpoly.edu/OntologyTutorial/family_example.owl#age ?a2&:(< ?a2 ?a1))))
=>
(printout t "Min age " ?a1 crlf))
What error problem?
ERROR-1: [ARGACCES5]function >= expected argument #2 to be of type integer or float.
ERROR-2: [CSTRCPSR1] expected the begining of a contrust.
How to fix this error?
For the first error, you're passing a non-numeric argument as the second argument into the >= function. When an error occurs within a construct, CLIPS will show you what's been parsed to help you locate the problem:
CLIPS>
(defrule example
(test (>= 3 a))
=>)
[ARGACCES5] Function >= expected argument #2 to be of type integer or float
ERROR:
(defrule MAIN::example
(test (>= 3 a)
CLIPS>
Typically the second error occurs when you have an extra or missing parenthesis when loading constructs. For example, if you create a file named example.clp with the following contents:
(defrule example-1 =>)
(defrule example-2 =>)
) ; Extra parenthesis
(defrule example-3 =>)
(defrule example-4 =>)
You'll get this error when you try to load it:
CLIPS> (watch compilations)
CLIPS> (load "example.clp")
Defining defrule: example-1 +j+j
Defining defrule: example-2 +j
[CSTRCPSR1] Expected the beginning of a construct.
Defining defrule: example-3 +j
Defining defrule: example-4 +j
FALSE
CLIPS>
If you're watching compilations, you can get a better idea of where the error is occurring. In this case it's between the rules example-2 and example-3.
I need some function which among other stuff would define a new global symbol. So that I could use it like this:
(define (func-prototype symbol value comment)
(define symbol value) ; this should somehow be reformulated
(format "~a=~a !~a\n" symbol value comment))
(define string-list (map func-prototype
'((s1 1 "first value")
(s2 20 "second value")
(s3 300 "third value))))
and be able to get the following results:
> string-list
'("s1=1 !first value\n"
"s2=20 !second value\n"
"s3=300 !third value\n")
> s1
1
> s2
20
> s3
300
Can this be implemented as a function or it is possible to do that only with the help of macros? Could you please suggest any possible implementations or at least give some hints/references that might be helpful?
I'd rethink the general approach, making it simpler. My suggestion: define a global hash table and inside the function add bindings to it, for example:
(define value-map (make-hash))
(define (func-prototype symbol value comment)
(hash-set! value-map symbol value)
(format "~a=~a !~a\n" symbol value comment))
Use it like this:
(define string-list
(map (lambda (lst)
(apply func-prototype lst))
'((s1 1 "first value")
(s2 20 "second value")
(s3 300 "third value"))))
string-list
=> '("s1=1 !first value\n"
"s2=20 !second value\n"
"s3=300 !third value\n")
And wherever you need to refer to one of the symbols in the hash table, do this:
(define (get key)
(hash-ref value-map key))
(get 's1)
=> 1
(get 's2)
=> 20
(get 's3)
=> 300
In general it is not possible to accomplish what you are trying to accomplish in the way you described. Your only hope would be to write stuff out to a file and then load that file into an interactive session. But even then.
In scheme you can't introduce top-level names, such as your desired s1, s2, and s3, except at the top-level. To do so, you could define a macro as:
>(define-syntax define-foo
(syntax-rules ()
((_ name value)
(define name value))))
>(define-foo s1 1)
<undefined>
> s1
1
If you try to use that macro in a function, it is no dice because the body of a function must end with an expression and any definition forms, like what the above macro would expand into, become local variables. That is:
(define (func-prototype name value comment)
(define-foo name value)
name)
>(func-prototype 's1 1 "com")
1
> s1
<error>
One approach that you could take that would work if your string-list is a constant would be as such:
> (define-syntax declare-variables
(syntax-rules ()
((_ (name value comment) ...)
(begin
(define name value)
...))))
> (declare-variables (s1 1 "com") (s2 20 "com") (s3 300 "com"))
> s1
1
This gets it done (I've ignored using 'comment') but, as I said, requires a compile time string-list.
One possibility you might think would work, but wouldn't, would be to use eval as:
(eval '(define s1 1) (environment ...))
but 'eval' only works for expressions, not declarations. Which gets me back to 'load' as a possibility.
First, consider whether you really want to do this, or whether a different solution (like a hash table) would work as well.
You can do this with reflection and dynamic evaluation using the eval procedure.
;; define-variable-with-value! : symbol any -> void
(define (define-variable-with-value! name value)
(eval `(define ,name (quote ,value))))
The quote is important; otherwise you risk reinterpreting a value as an expression to evaluate. To see the difference, consider the example
(define-variable-with-value! 'x (list 'error "kaboom"))