CLIPS Error:Template xxx does not exist for assert - rules

CLIPS version: 6.31
language: c++ clips C API
Why am I getting this error? How should I fix this error?
[FACTRHS1] Template be-contact-model.riskLevel does not exist for assert.
Function load-facts encountered an error
The process is as follows: Firstly, I create a CLIPS environment from the full clips rule code using the ClipsEnvLoadFromString function, I will get a normal result in this CLIPS environment using the EnvLoadFactsFromString function.Next I want to copy more than one CLIPS environment,
so I save the rules in a binary image file using the EnvBsave function and then I load a new environment from a binary file using EnvBload function, and then I use the EnvLoadFactsFromString function to load the user facts.But the EnvLoadFactsFromString function return false, and the cli stdout get the error string:
[FACTRHS1] Template be-contact-model.riskLevel does not exist for assert.
Function load-facts encountered an error
The facts parameter of the EnvLoadFactsFromString function as following:
(appId "TEST")
(be-contact-model.riskLevel "PASS")
(be-contact-model.score 0)
(channel "POST_TEXT.RlokQwRlVjUrTUlkIqOg.COMMENT")
(constantKey "constantKey")
(contact.model "contact_detector(GO)")
(contact.nicknameResult.has_contact FALSE)
(contact.nicknameResult.has_qq FALSE)
(contact.nicknameResult.has_tel FALSE)
(contact.nicknameResult.has_url FALSE)
(contact.nicknameResult.has_wechat FALSE)
(contact.riskLevel "PASS")
(contact.score 0)
(contact.textResult.baidusearch.REJECT_LEVEL 0)
(contact.textResult.has_contact FALSE)
(contact.textResult.has_qq FALSE)
(contact.textResult.has_tel FALSE)
(contact.textResult.has_url FALSE)
(contact.textResult.has_wechat FALSE)

Once you load a binary image, you can't create any new constructs. Ordered facts and patterns (those that don't have a corresponding deftemplate construct) automatically create a deftemplate. If your rules haven't already created this automatic deftemplate, it can't be created after you've already loaded a binary image:
CLIPS (6.31 6/12/19)
CLIPS> (bsave example.bin)
TRUE
CLIPS> (bload example.bin)
TRUE
CLIPS> (assert (be-contact-model.riskLevel "PASS"))
[FACTRHS1] Template be-contact-model.riskLevel does not exist for assert.
CLIPS>
If you have a rule that matches the ordered fact, you can assert this type of fact after you've loaded the binary image.
CLIPS> (clear)
CLIPS>
(defrule r1
(be-contact-model.riskLevel ?)
=>)
CLIPS> (bsave example.bin)
TRUE
CLIPS> (clear)
CLIPS> (bload example.bin)
TRUE
CLIPS> (assert (be-contact-model.riskLevel "PASS"))
<Fact-0>
CLIPS>
So the fact that you're getting an error message would indicate that you're attempting to assert a fact that none of your rules can match.
It looks like your facts are attribute/value pairs, so one thing you can do if you're asserting facts that no rule can match is to create a generic deftemplate for representing all of them:
CLIPS> (clear)
CLIPS> (deftemplate av (slot a) (slot v))
CLIPS> (assert (av (a be-contact-model.riskLevel) (v "PASS")))
<Fact-1>
CLIPS>

Related

Call one rule from another in clips

I wanted to know if there is any possibility of firing a rule from the RHS of another rule.
for example,
rule 1:
(defrule printHello
=>
(printout t " Hello World" crlf ))
rule 2:
(defrule printName
=>
/* tigger rule 1 */)
Expert systems are knowledge representation engines. They use knowledge (static and dynamic) to represent their internal state. In CLIPS, dynamic knowledge is represented with facts.
You can use a custom dedicated fact for that.
(defrule printHello
(print hello)
=>
(printout t " Hello World" crlf))
(defrule printName
=>
(assert (print hello)))

Backquote symbol list ending in period

I'm curious if there is a way to end a backquoted symbol list with a period following a comma inserted value.
Here is the sample code:
(defparameter *things* '(book pencil shoe))
(defun inspect-item (item things)
(if (member item things)
`(you pick up the ,item and yeet it out the window.)
`(only realize the truth... there is no ,item.)))
This will succeed (print (inspect-item 'book *things*)) and it produces the symbol list (YOU PICK UP THE BOOK AND YEET IT OUT THE WINDOW.). I assume in this case that the period is part of the symbol WINDOW. (as confirmed using the last function).
However, this will fail (print (inspect-item 'spoon *things*)) claiming that variable ITEM. has no value (Because it thinks the name is item.). Leaving a space between item and the period gives the error illegal end of dotted list which I assume is because it is assuming I'm using dotted list syntax.
Is there any way to get it to produce the symbol I want at the end (BOOK.)?
Possible requirements for a solution
You need to create a new symbol based on an old one:
the same name, with a . appended
probably in the same package
Period as a symbol
Note that you can write a symbol with the period as a name using an escaped symbol: |.| or \..
CL-USER 17 > (let ((item 'foobar))
`(only realize the truth... there is no ,item \.))
(ONLY REALIZE THE TRUTH... THERE IS NO FOOBAR \.)
princ prints without escape characters:
CL-USER 18 > (princ '(ONLY REALIZE THE TRUTH... THERE IS NO FOOBAR \.))
(ONLY REALIZE THE TRUTH... THERE IS NO FOOBAR .) ; <- printed output
(ONLY REALIZE THE TRUTH... THERE IS NO FOOBAR \.) ; <- REPL value
Solution
CL-USER 19 > (defun add-suffix (symbol suffix)
(intern (concatenate 'string
(symbol-name symbol)
(symbol-name suffix))
(symbol-package symbol)))
ADD-SUFFIX
CL-USER 20 > (let ((item 'tree))
`(we went to the ,(add-suffix item '|.|)))
(WE WENT TO THE TREE.)
It can also be useful to use the flexibility of format instead of using concatenate.
CL-USER 22 > (defun add-suffix (symbol suffix)
(intern (format nil "~a~a" symbol suffix)
(symbol-package symbol)))
ADD-SUFFIX
I think that the real problem lies in the attempt to produce text just as the printed representation of a list of symbols. Those are completely different things. The only reason to do it like this could be as some kind of exercise. There are a number of introductory texts that do that kind of thing.
Instead, I'd advise to actually produce text, i. e. strings. You might use the format function that is quite flexible for inserting variable things:
(defparameter *things* '("book" "pencil" "shoe"))
(defun inspect-item (item things)
(if (member item things :test #'string-equal)
(format nil
"You pick up the ~a and yeet it out the window."
item)
(format nil
"Only realize the truth… there is no ~a."
item)))
I partly agree with Svante that turning lists of symbols into text is often the wrong thing. On the other hand things like parsers &c often want to think in terms of symbols rather than strings as symbols have nice properties like (eq a b) working the way you would hope.
That being said, here's an alternative approach: create a list of words and then have a function which turns them into a string representing a sentence, adding appropriate punctuation and capitalization.
(defparameter *things* '(book pencil shoe))
(defun inspect-item (item things)
(sentencify (if (member item things)
`(you pick up the ,item and yeet it out the window)
`(only realize the truth... there is no ,item))))
(defun sentencify (slist &key (question nil))
(format nil "~{~A~^ ~}~A"
(loop for first = t then nil
for w in slist
for ws = (typecase w
(symbol (symbol-name w))
(string w)
(t w))
collect (typecase ws
(string (if first
(string-capitalize ws)
(string-downcase ws)))
(t ws)))
(if question "?" ".")))
And now:
> (inspect-item 'book *things*)
"You pick up the book and yeet it out the window."
> (inspect-item 'bok *things*)
"Only realize the truth... there is no bok."
> (inspect-item '(x . y) *things*)
"Only realize the truth... there is no (x . y).

How to require keyword arguments in Common Lisp?

Given
(defun show-arg (a)
(format t "a is ~a~%" a))
(defun show-key (&key a)
(format t "a is ~a~%" a))
evaluating
(show-arg)
will lead to an error saying "invalid number of arguments: 0", where
(show-key)
will display a is NIL
How can I get SHOW-KEY to signal an error like SHOW-ARG does? Is there a way other than using (unless a (error "a is required")) in the function body? I am very fond of keyword arguments and use them constantly, and almost always want them to be required.
Keyword arguments are always optional, so you do need to manually check if they're given and signal an error if needed. It would be better to not require keyword arguments though. The compiler won't recognize them as required and thus won't given you an error message for missing arguments at compile time.
If you do want to require them, you can specify the arguments with a three element list; the first element being the argument, the second is the default value and the third is a variable that will be true if the argument was given. Checking the third element is better than checking the keyword itself, because then you can tell the difference between a NIL that was the default, and a NIL that the user gave as an argument.
(defun foo (&key (keyarg nil keyargp))
(unless keyargp (error "KEYARG is required."))
(* keyarg 2))
Edit
Now that I think about this a bit more, there actually is a way to get compile time errors for missing keyword arguments. Define a compiler macro for the function:
(defun foo (&key a b c d)
(* a b c d))
(define-compiler-macro foo (&whole whole &key (a nil ap) (b nil bp)
(c nil cp) (d nil dp))
(declare (ignore a b c d))
(unless (and ap bp cp dp)
(error "Missing arguments..."))
whole)
One possibility would be:
(defun foo (&key (arg1 (error "missing arg1 in call to function foo")))
arg1)
Using it:
CL-USER 80 > (foo)
Error: missing arg1 in call to function foo
1 (abort) Return to level 0.
2 Return to top loop level 0.
This will give an error at runtime, unfortunately not at compile time.

SBCL warning that a variable is defined but never used

I'm getting a warning from the sbcl compiler, that a variable has been defined but is not used. And the compiler is right. I want to get rid of the warning, but don't know how to do it. Here is an example:
(defun worker-1 (context p)
;; check context (make use of context argument)
(if context
(print p)))
(defun worker-2 (context p)
;; don't care about context
;; will throw a warning about unused argument
(print p))
;;
;; calls a given worker with context and p
;; doesn't know which arguments will be used by the
;; implementation of the called worker
(defun do-cmd (workerFn context p)
(funcall workerFn context p))
(defun main ()
(let ((context ()))
(do-cmd #'worker-1 context "A")
(do-cmd #'worker-2 context "A")))
The do-cmd-function expects worker-functions that implement a specific interface f(context p).
The sbcl compiler throws the following warning:
in: DEFUN WORKER-2
; (DEFUN WORKER-2 (CONTEXT P) (PRINT P))
;
; caught STYLE-WARNING:
; The variable CONTEXT is defined but never used.
;
; compilation unit finished
; caught 1 STYLE-WARNING condition
You need to declare that the parameter is intentionally ignored.
(defun worker-2 (context p)
(declare (ignore context))
(print p))
ignore will also signal a warning if you do use the variable. To suppress warnings in both cases, you can use the declaration ignorable, but this should only be used in macros and other such cases where it's not possible to determine whether the variable will be used at the point of its declaration.
In case you are not yet familiar with declare, note that it is not an operator, and instead can only appear in certain locations; in particular, it must be located before all forms in the defun body, though it can be either above or below a documentation string.

Can you get the "code as data" of a loaded function in Clojure?

To put it another, way, "Okay, so code is data..."
That thread addresses how to read from a source file, but I'm wondering how to get the s-expression of an already-loaded function into a data structure that I can read and manipulate.
In other words, if I say,
(defn example [a b] (+ a b))
can't I get that list at runtime? Isn't this the whole point of "code as data"?
This is really a general Lisp question, but I'm looking for an answer in Clojure.
You can use the clojure.repl/source macro to get the source of a symbol:
user> (source max)
(defn max
"Returns the greatest of the nums."
{:added "1.0"
:inline-arities >1?
:inline (nary-inline 'max)}
([x] x)
([x y] (. clojure.lang.Numbers (max x y)))
([x y & more]
(reduce1 max (max x y) more)))
nil
But this is only part of the answer. AFAICT source looks up the source filename and line number that define the given symbol, and then prints the source code from the file. Therefore, source will not work on symbols that you do not have the source for, i.e. AOT-compiled clojure code.
Coming back to your original question, you can think of source as reading the meta data associated with the given symbol and simply printing that. I.e. it's cheating. It's not in any way returning "code as data" to you, where with code I mean a compiled clojure function.
In my mind "code as data" refers to the feature of lisps where source code is effectively a lisp data structure, and therefore it can be read by the lisp reader. That is, I can create a data structure that is valid lisp code, and eval that.
For example:
user=> (eval '(+ 1 1))
2
Here '(+ 1 1) is a literal list which gets read by the clojure reader and then evaluated as clojure code.
Update: Yehonathan Sharvit was asking in one of the comments if it's possible to modify the code for a function. The following snippet reads in the source for a function, modifies the resulting data structure, and finally evaluates the data structure resulting in a new function, my-nth, being defined:
(eval
(let [src (read-string (str (source-fn 'clojure.core/nth) "\n"))]
`(~(first src) my-nth ~#(nnext src))))
The syntax-quote line replaces nth with my-nth in the defn form.
You can get the source in recent versions of clojure with the source function.
user=> (source nth)
(defn nth
"Returns the value at the index. get returns nil if index out of
bounds, nth throws an exception unless not-found is supplied. nth
also works for strings, Java arrays, regex Matchers and Lists, and,
in O(n) time, for sequences."
{:inline (fn [c i & nf] `(. clojure.lang.RT (nth ~c ~i ~#nf)))
:inline-arities #{2 3}
:added "1.0"}
([coll index] (. clojure.lang.RT (nth coll index)))
([coll index not-found] (. clojure.lang.RT (nth coll index not-found))))
nil
to get the string as a value you can wrap this in with-out-str:
user=> (with-out-str (source nth))
"(defn nth\n \"Returns the value at the index. get returns nil if index out of\n bounds, nth throws an exception unless not-found is supplied. nth\n also works for strings, Java arrays, regex Matchers and Lists, and,\n in O(n) time, for sequences.\"\n {:inline (fn [c i & nf] `(. clojure.lang.RT (nth ~c ~i ~#nf)))\n :inline-arities #{2 3}\n :added \"1.0\"}\n ([coll index] (. clojure.lang.RT (nth coll index)))\n ([coll index not-found] (. clojure.lang.RT (nth coll index not-found))))\n"
user=>
That was my message; nice to meet you ;-) BTW, the references given in that thread for answers were excellent reading; so if you're interested, you might want to take the time to read them. Back to your question though source seems to work for code that was loaded through a file, but it doesn't work in all cases. I think, specifically, it doesn't work for functions defined in the repl.
user=> (def foo (fn [] (+ 2 2)))
#'user/foo
user=> (source foo)
Source not found
nil
user=> (defn foo2 [] (+ 2 2))
#'user/foo2
user=> (source foo2)
Source not found
nil
Digging a little bit...
user=> (source source)
(defmacro source
"Prints the source code for the given symbol, if it can find it.
This requires that the symbol resolve to a Var defined in a
namespace for which the .clj is in the classpath.
Example: (source filter)"
[n]
`(println (or (source-fn '~n) (str "Source not found"))))
nil
user=> (source clojure.repl/source-fn)
(defn source-fn
"Returns a string of the source code for the given symbol, if it can
find it. This requires that the symbol resolve to a Var defined in
a namespace for which the .clj is in the classpath. Returns nil if
it can't find the source. For most REPL usage, 'source' is more
convenient.
Example: (source-fn 'filter)"
[x]
(when-let [v (resolve x)]
(when-let [filepath (:file (meta v))]
(when-let [strm (.getResourceAsStream (RT/baseLoader) filepath)]
(with-open [rdr (LineNumberReader. (InputStreamReader. strm))]
(dotimes [_ (dec (:line (meta v)))] (.readLine rdr))
(let [text (StringBuilder.)
pbr (proxy [PushbackReader] [rdr]
(read [] (let [i (proxy-super read)]
(.append text (char i))
i)))]
(read (PushbackReader. pbr))
(str text)))))))
nil
So yeah, it looks like it tries to load the source file off the classpath to try to spit it out for you. One thing I've learned when working with Clojure is that 9 times out of 10 it is useful to look at the source.

Resources