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>
Related
Just started learning and coding lisp,
I'm trying to create a program that will continuously accept a number and stops only if and only if the last input number is twice the previous number.
Here's my code
----------
(let((a 0)
(b 0)
(count 0))
(loop
(= a b))
(princ"Enter Number: ")
(defvar a(read))
(format t "~% a = ~d" a)
(setq count (1+ count))
(while
(!= b(* a 2) || <= count 1)
(princ "Program Terminated Normally")
)
Thank you
a bit feedback
(let ((a 0)
(b 0)
(count 0))
(loop
(= a b)) ; here the LOOP is already over.
; You have a closing parenthesis
; -> you need better formatting
(princ"Enter Number: ")
(defvar a(read))
(format t "~% a = ~d" a)
(setq count (1+ count))
(while
(!= b(* a 2) || <= count 1)
(princ "Program Terminated Normally")
)
some improved formatting:
(let ((a 0)
(b 0)
(count 0))
(loop
(= a b)) ; LOOP ends here, that's not a good idea
(princ "Enter Number: ")
(defvar a(read)) ; DEFVAR is the wrong construct,
; you want to SETQ an already defined variable
(format t "~% a = ~d" a)
(setq count (1+ count))
(while ; WHILE does not exist as an operator
(!= b(* a 2) || <= count 1) ; This expression is not valid Lisp
(princ "Program Terminated Normally")
)
You may need to learn a bit more Lisp operators, before you really can write such loops. You also may want to use Lisp interactively and try out things, instead of trying to write code into an editor and never get feedback from a Lisp...
Here's an answer which definitely is not how you would do this in real life, but if you understand what it does you will understand one of the two big important things about Lisps.
(If you understand why the equivalent program would not work reliably in Scheme you'll also understand one of the important things about writing safe programs! Fortunately this is Common Lisp, not Scheme, so it's OK here.)
First of all let's write a little helper function to read integers. This is just fiddly detail: it's not important.
(defun read-integer (&key (prompt "Integer: ")
(stream *query-io*))
;; Read an integer. This is just fiddly details
(format stream "~&~A" prompt)
(values (parse-integer (read-line stream))))
OK, now here's a slightly odd function called mu (which stands for 'mutant U'):
(defun mu (f &rest args)
(apply f f args))
And now here is our program:
(defun read-integers-until-double-last ()
(mu (lambda (c getter current next factor)
(if (= next (* current factor))
(values current next)
(mu c getter next (funcall getter) factor)))
#'read-integer
(read-integer)
(read-integer)
2))
And here it is working:
> (read-integers-until-double-last)
Integer: 0
Integer: 4
Integer: 3
Integer: -2
Integer: -4
-2
-4
For extra mysteriosity you can essentially expand out the calls to mu here, which makes it either more clear or less clear: I'm not quite sure which:
(defun read-integers-until-double-last ()
((lambda (c)
(funcall c c
#'read-integer
(read-integer)
(read-integer)
2))
(lambda (c getter current next factor)
(if (= next (* current factor))
(values current next)
(funcall c c getter next (funcall getter) factor)))))
Again, this is not how you do it in real life, but if you understand what this does and how it does it you will understand quite an important thing about Lisps and their theoretical underpinnings. This is not all (not even most) of the interesting things about them, but it is a thing worth understanding, I think.
I am idly exploring PicoLisp, and find myself perplexed about how to write meta-programming functions that would traditionally be handled with macros (in other lisp dialects). The biggest source of concern for me is that I do not see how I can prevent variable name shadowing. Reviewing the examples in Metaprogramming 101 has, if anything, just left me more confused.
Examples on how to implement the function mapeach, as seen in the linked article:
[de mapeach "Args" # expression
(let [(#Var #List . #Body) "Args"]
(macro
(mapcar
'((#Var) . #Body)
#List ]
(de mapeach "Args"
(mapcar
(cons (cons (car "Args")) (cddr "Args"))
(eval (cadr "Args")) ) )
(de mapeach "Args"
(mapcar
'(("E")
(bind (car "Args")
(set (car "Args") "E")
(run (cddr "Args")) ) )
(eval (cadr "Args")) ) )
(de mapeach "Args"
(let "Vars" (pop '"Args")
(apply mapcar
(mapcar eval (cut (length "Vars") '"Args"))
(cons "Vars" "Args") ) ) )
I have tested each of these with the call (let "Args" * (mapeach N (1 2 3) ("Args" N N))). As expected, the PicoLisp interpreter (started with the command pil +) experiences a segfault and crashes. I assume this is because mapeach's "Args" shadows the "Args" defined at call point.
I also tried both of their implementations of map# (the "cuter" alternative to mapeach).
(de map# "Args"
(mapcar
'(("E") (and "E" (run (cdr "Args")))) # 'and' sets '#'
(eval (car "Args")) ) )
(de map# "Args"
(mapcar
'((#) (run (cdr "Args")))
(eval (car "Args")) ) )
I used (let "Args" * (map# (1 2 3) ("Args" # #))) to test each of those implementations. Bizarrely, the first time I tested the first implementation, not only did it not segfault, it actually produced the correct result (1 4 9). Each subsequent test has resulted in a segfault. For clarity, the snippet from the prompt:
: (de map# "Args"
(mapcar
'(("E") (and "E" (run (cdr "Args")))) # 'and' sets '#'
(eval (car "Args")) ) )
-> map#
: (let "Args" * (mapeach N (1 2 3) ("Args" N N)))
!? (mapeach N (1 2 3) ("Args" N N))
mapeach -- Undefined
?
: (let "Args" * (map# (1 2 3) ("Args" # #)))
-> (1 4 9)
I believe that the segfault was somehow prevented by the call to the (then) undefined function mapeach, I also tried (ooga booga), which similarly prevented the segfault. If I do not have the erroneous call separating the definition from the proper call, a segfault always occurs.
This ultimately culminates in 2 questions:
How can I prevent name shadowing? Clearly the examples do not succeed in that regard.
Why does that call to map# not result in a segfault?
According to this "The index for transient symbols is cleared automatically before and after loading a source file, or it can be reset explicitly with the ==== function". It doesn't specify any way that it is automatically cleared during regular REPL usage, which is the context in which I was testing this.
This code runs properly:
[de mapeach "Args" # expression
(let [(#Var #List . #Body) "Args"]
(macro
(mapcar
'((#Var) . #Body)
#List ]
(====)
(let "Args" * (mapeach N (1 2 3) ("Args" N N)))
It also runs as expected without the call to ====, but only if the call to mapeach is not in the same file.
To address the 2 parts of my question:
You can prevent name shadowing by using transient symbols either in different files, or followed by a call to ====.
Those calls likely worked because the debugger clears the index which contains the transient symbols.
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))
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.