CLIPS - if then else function gives [CSTRCPSR1] err - if-statement

Here is the error summary:
CLIPS> (load "C:/Users/labor/Desktop/Witek/projekt.CLP")
Defining defrule: R1 +j+j
Defining defrule: R2 +j+j
Defining defrule: R3 =j+j+j
Defining defrule: imie-if =j=j+j+j
[CSTRCPSR1] Expected the beginning of a construct.
And here is the code for my CLIPS program. Basically I want it to react different if the name and last name are different from Abraham Lincoln.
(defrule R1
(initial-fact)
=>
(printout t "Enter your name:" crlf)
(bind ?name (read))
(assert (name ?name)))
(defrule R2
(name ?name)
=>
(printout t "Enter your last name" crlf)
(bind ?lastnm (read))
(assert (lastnm ?lastnm)))
(defrule R3
(and(name ?name)(lastnm ?lastnm))
=>
(printout t "How old are you " ?name "?" crlf)
(bind ?age (read))
(assert (age ?age)))
(defrule name-if
(name ?name)(lastnm ?lastnm)(age ?age)
=>
(if(and(eq ?name Abraham)(eq ?lastnm Lincoln))
then (printout t "Hello " ?name " " ?lastnm ", you are " ?age " years old bro" crlf))
else (printout t "Hello " ?name " " ?lastnm ", you are " ?age " years old" crlf)))
I copied the if statement logic from some webpage and I am not quite sure what, in this case, 'eq' stands for... i'd appreciate if you could additionally explain the role of it.
Regards,
W

You have an extra right parenthesis at the end of the then clause that is causing the issue. The Mac OS and Window CLIPS IDEs have a balance command that you can use to see if the parentheses are properly balanced within a construct. Just click inside a construct and apply the balance command several times until the entire construct is selected. If you place the cursor by the then keyword and balance, you'll see that the if statement is closed by the parenthesis at the end of the then clause and the else clause is left dangling.
The corrected rule is:
(defrule name-if
(name ?name)
(lastnm ?lastnm)
(age ?age)
=>
(if (and (eq ?name Abraham)
(eq ?lastnm Lincoln))
then
(printout t "Hello" ?name " " ?lastnm ", you are " ?age " years old bro" crlf)
else
(printout t "Hello " ?name " " ?lastnm ", you are " ?age " years old" crlf)))
The eq predicate is short for equals. Unlike the = predicate that expects numeric arguments, eq compares values of any type.

Related

Return true/false on [strings in a cell] being found in [strings in another cell]?

Cell A1 contains multiple strings, eg "CAT DOG RAT GNU";
Cell B1 contains multiple strings, eg "RAT CAT";
How can I run a test (using formula in C1) to find if all the strings in B1 are present in cell A1?
Returning true/false would be good
Strings not necessarily in the same order, as example above
The number of items can vary
Multiple instances not a problem, so long as they're there
But returns true only if all items in cell B1 are present in cell A1.
So far I've tried transposed-split arrays with vlookups and matches, counts, etc, but nothing working for me. (And maybe regex won't do it as can't loop for each string?)
you can try:
=ARRAYFORMULA(IF(PRODUCT(N(NOT(ISNA(REGEXEXTRACT(SPLIT(B1, " "),
SUBSTITUTE(A1, " ", "|"))))))=1, TRUE))
for more precision you can do:
=ARRAYFORMULA(IF(PRODUCT(N(NOT(ISNA(REGEXEXTRACT(SPLIT(B1, " "),
"^"&SUBSTITUTE(A1, " ", "$|^")&"$")))))=1, TRUE))
then for case insensivity:
=ARRAYFORMULA(IF(PRODUCT(N(NOT(ISNA(REGEXEXTRACT(SPLIT(LOWER(B1), " "),
"^"&SUBSTITUTE(LOWER(A1), " ", "$|^")&"$")))))=1, TRUE))
and true ArrayFormula would be:
=ARRAYFORMULA(IF((A1:A<>"")*(B1:B<>""), IF(REGEXMATCH(TRANSPOSE(QUERY(TRANSPOSE(IFERROR(
REGEXMATCH(IF(SPLIT(B1:B, " ")<>"", SPLIT(LOWER(B1:B), " "), 0),
"^"&SUBSTITUTE(LOWER(A1:A), " ", "$|^")&"$"))),,999^99)), "FALSE"), FALSE, TRUE), ))

Keep quotation marks in a formatted list Racket

How do you print a formatted string with quotation marks, and without the backward slashes?
For example, when I enter
(format "say ~a" "hello there!")
I want to get
" say "hello there!" "
I want the quotation marks wrapped around "hello there" as the way I typed in. However, if I format it as a string, it turns out like this:
"say \"hello there!\""
Is there a way to keep the quotation marks without having the backward slash?
evaluating strings, and print/println print the quote " as\".
Maybe you're looking for display/displayln:
(displayln (format "say \"~a\"" "hello there!"))
; => say "hello there!"
use ~s instead of ~a
> (format "say ~s" "hello there!")`
"say \"hello there!\""

Converting a javascript function using Clojure

I'm kind new in the Lisp/Functional/Clojure world and I've a JS function:
function buildString(someInteger) {
var question = "Initial text";
if (someInteger == 1) {
question += " put this string ";
} else if(someInteger == 2) {
question += " oh! another string ";
} else if(someInteger == 3) {
question += " guess what? ";
}
return question;
}
What could be a good way to rewrite this to a Clojure function? I already have some code using the "cond" Clojure macro, but I'm not sure about the immutable string "question":
(defn build-string [some-integer]
(let [question "Initial text"]
(cond
(= some-integer 1) (str question "Add string one")
(= some-integer 2) (str question "Add string two")
(= some-integer 3) (str question "Add string three"))))
You want the cond-> macro:
(defn build-string [some-integer]
(let [question "Initial text; "]
(cond-> question
(= some-integer 1) (str "Add string one")
(= some-integer 2) (str "Add string two")
(= some-integer 3) (str "Add string three"))))
(build-string 1) => "Initial text; Add string one"
(build-string 2) => "Initial text; Add string two"
(build-string 3) => "Initial text; Add string three"
although in this case plain old cond will work:
(defn build-string [some-integer]
(let [question "Initial text; "]
(cond
(= some-integer 1) (str question "Add string one")
(= some-integer 2) (str question "Add string two")
(= some-integer 3) (str question "Add string three"))))
#cfrick makes a good point:
(defn build-string-map [some-integer]
(let [question "Initial text; "
data {1 "Add string one"
2 "Add string two"
3 "Add string three"}
suffix (get data some-integer)
result (str question suffix)]
result))
(build-string-map 1) => "Initial text; Add string one"
(build-string-map 2) => "Initial text; Add string two"
(build-string-map 3) => "Initial text; Add string three"
Be sure to look at the
Clojure CheetSheet
ClojureScript CheetSheet
clojure.org
clojurescript.org
Your cond form is fine, but you can use case here:
(defn build-string [some-integer]
(str "Initial text"
(case some-integer
1 "Add string one"
2 "Add string two"
3 "Add string three")))
Your “immutable string question”: in contrast to your JavaScript version, none of the operators you or I have been using modify any of their arguments. For example, Clojure's str builds a new string, but JavaScript's += modifies a variable. You need not worry: it is not a mistake to modify things in Clojure that you would need to keep an eye out for, but rather the language makes it difficult to do it in the first place. If you see a simple function using standard operators, it is very improbable for it to be doing something unsafe.
If you have just some "equal number" checks, i'd just go with a map. E.g.
(str "Initial text" ({1 "Add string one" 2 "Add string two" 3 "Add string three"} some-integer))
Or just go with condp. E.g.
(defn build-string
[some-integer]
(str "Initial text"
(condp = some-integer
1 "Add string one"
2 "Add string two"
3 "Add string three"
nil)))
(map build-string (range 4))
; => ("Initial text" "Initial textAdd string one" "Initial textAdd string two" "Initial textAdd string three")
I think the keypoint here is to eliminate duplication; not only eliminate the "length" but also eliminate the "width" of your code.

How to convert a list of string to a string in racket?(leaving the spaces intact)

How do I convert a list of strings into a string in DrRacket? For example, if I have
'("44" "444") convert it into "44 444"?
I tried string-join, but it takes a delimiter and if I put one it replaces the space with the delimiter and if I use "" for the delimiter it simply gets rid of it.
In fact string-join is the right procedure for using in this case, simply use " " (a single space) as delimiter:
(string-join '("44" "444") " ")
=> "44 444"
Just to clarify: in a list the spaces between elements are not considered part of the list, they're there to separate the elements. For example, all these lists are equal and evaluate to the same value:
'("44""444")
'("44" "444")
'("44" "444")
If for some reason you want to consider the spaces as part of the list then you have to explicitly add them as elements in the list:
(define lst '("a" " " "b" " " "c" " " "d"))
(string-join lst "")
=> "a b c d"

difference/relation between str and print-str in Clojure

I was reading Volkmann's Clojure tutorial, in that tutorial it says the function print-str prints the content to a string that is returned. So does this mean that:
(print-str a b c ... ) == (str a " " b " " c " " ... )
I tried with my REPL and it behaved like I assumed above, but I just want to know if it really is, or I am missing something here...
The function print-str will return a string similar to what REPL would report if asked to evaluate the argument, e.g. for human consumption. The function str invokes the .toString of the object. In the case of a string argument, the result is the same as you point out.
This is not in general true for other objects
((juxt print-str str) 1N)
;=> ["1N" "1"]
((juxt print-str str) (java.util.Date.))
;=> ["#inst \"2013-07-19T01:47:00.784-00:00\"" "Thu Jul 18 20:47:00 CDT 2013"]