How to add together the elements on the same position CLIPS - list

I am new to clips and I have not idea how to iterate through lists correctly and to add them together and put the sum on the same position.
I have two lists defined as facts and I want to create a list that will have the sums of the lists of the elements on the same position.
Ex:
(deffacts lists
(list 1 2 3 4)
(list 1 2 3 4)
)
And the result should be : (listSum 2 4 6 8)
Any help or advice is welcomed. Thank you!

Here's a function that will merge two lists:
CLIPS (6.31 6/12/19)
CLIPS>
(deffunction add-merge (?m1 ?m2)
;; Get the lengths of the multifields
(bind ?l1 (length$ ?m1))
(bind ?l2 (length$ ?m2))
;; Swap values if the first multifield is not the largest
(if (> ?l2 ?l1)
then
(bind ?tmp ?l1)
(bind ?l1 ?l2)
(bind ?l2 ?tmp)
(bind ?tmp ?m1)
(bind ?m1 ?m2)
(bind ?m2 ?tmp))
;; Merge the values
(bind ?rv (create$))
(loop-for-count (?i ?l2)
(bind ?rv (create$ ?rv (+ (nth$ ?i ?m1) (nth$ ?i ?m2)))))
(loop-for-count (?i (+ ?l2 1) ?l1)
(bind ?rv (create$ ?rv (nth$ ?i ?m1))))
?rv)
CLIPS> (add-merge (create$ 1 2 3 4) (create$ 5 6 7 8))
(6 8 10 12)
CLIPS>
With the default settings in CLIPS, you can't have duplicate facts, so if you want two lists with the same values you need to create a slot that will contain a unique value for each list:
CLIPS>
(deftemplate list
(slot id (default-dynamic (gensym*)))
(multislot values))
CLIPS>
(deffacts lists
(list (id l1) (values 1 2 3 4))
(list (id l2) (values 1 2 3 4)))
CLIPS>
Then you can create a rule which will merge two lists:
CLIPS>
(defrule merge
(sum-lists ?l1 ?l2)
(list (id ?l1) (values $?v1))
(list (id ?l2) (values $?v2))
=>
(assert (list (values (add-merge ?v1 ?v2)))))
CLIPS> (reset)
CLIPS> (assert (sum-lists l1 l2))
<Fact-3>
CLIPS> (run)
CLIPS> (facts)
f-0 (initial-fact)
f-1 (list (id l1) (values 1 2 3 4))
f-2 (list (id l2) (values 1 2 3 4))
f-3 (sum-lists l1 l2)
f-4 (list (id gen1) (values 2 4 6 8))
For a total of 5 facts.
CLIPS>

Related

How to transform list into sub lists?

((1 2 3)
(2 3 4)
(3 4 5)
(4 5 6))
from
(1 2 3 4 5 6)
And what is the type of such operation?
What I tried:
(loop
:with l2 = '()
:with l1 = '(1 2 3 4 5 6)
:for i :in l1
:do (push (subseq l1 0 3) l2))
You're pushing the same sublist every time through the loop.
You can use :for sublist on to loop over successive tails of a list.
And use :collect to make a list of all the results, rather than pushing onto your own list
(loop
:for l1 on '(1 2 3 4 5 6)
:if (>= (length l1) 3)
:collect (subseq l1 0 3)
:else
:do (loop-finish))
Alternatively use map:
(let ((l '(1 2 3 4 5 6)))
(map 'list #'list l (cdr l) (cddr l)))
;; ((1 2 3) (2 3 4) (3 4 5) (4 5 6))
You can read it as:
for list l with values (1 2 3 4 5 6)
map over the list and its two successive cdrs
by applying #'list on the elements of the lists map is looping through in parallel
(stopping when shortest list is used up)
and collecting the results as/into a 'list
#WillNess suggested even simpler:
(let ((l '(1 2 3 4 5 6)))
(mapcar #'list l (cdr l) (cddr l)))
thanks! So then we could generalize using only map variants:
(defun subseqs-of-n (l n)
(apply #'mapcar #'list (subseq (maplist #'identity l) 0 n)))
(maplist #'identity l) is equivalent to (loop for sl on l collect sl).
However,
(loop for sl on l
for i from 0 to n
collect sl)
is better because it stops at n-th round of looping ...
First let's define a function take-n, which either returns n items or an empty list, if there are not enough items. It will not scan the whole list.
(defun take-n (n list)
(loop repeat n
when (null list) return (values nil nil)
collect (pop list)))
Then we move this function take-n over the list until it returns NIL.
(defun moving-slice (n list)
(loop for l on list
for p = (take-n n l)
while p
collect p))
Example:
CL-USER 207 > (moving-slice 3 '(1 2))
NIL
CL-USER 208 > (moving-slice 3 '(1 2 3))
((1 2 3))
CL-USER 209 > (moving-slice 3 '(1 2 3 4 5 6 7))
((1 2 3) (2 3 4) (3 4 5) (4 5 6) (5 6 7))
Here's a version of Barmar's answer (which should be the accepted one) which is a bit more general and only calls length once.
(defun successive-leading-parts (l n)
(loop repeat (1+ (- (length l) n))
for lt on l
collect (subseq lt 0 n)))
> (successive-leading-parts '(1 2 3 4) 3)
((1 2 3) (2 3 4))
> (successive-leading-parts '(1 2 3 4) 2)
((1 2) (2 3) (3 4))
Or the classical more C-like for-loop-ing with indexes to solve it.
But use it more on strings/vectors but less on lists, because its performance is
for lists quadratic
for vectors (strings!) linear, so preferably to be used with them!
credits and thanks to #WillNess who pointed both points out (see comments below).
(defun subseqs-of-n (ls n) ;; works on strings, too!
(loop :for i :from 0 :to (- (length ls) n)
:collect (subseq ls i (+ i n))))
So on vectors/strings use:
(subseqs-of-n "gattaca" 5)
;; ("gatta" "attac" "ttaca")

Common lisp identity-groups

I am a lisp beginner and i wrote a function to group equal adjacent items in a list. I would be grateful if Lisp experts could give me some advice about a better lispy writing of this function. Thanks in advance!
(defun identity-groups (lst)
(labels ((travel (tail group groups)
(cond ((endp tail) (cons group groups))
((equal (car tail) (car (last group)))
(travel (cdr tail) (cons (car tail) group) groups))
(t (travel (cdr tail) (list (car tail)) (cons group groups))))))
(reverse (travel (cdr lst) (list (car lst)) nil))))
(identity-groups '(1 3 5 4 4 4 4 5 1 2 2 2 1 2 3 3 3 3 3 4 5 6 7))
;; => ((1) (3) (5) (4 4 4 4) (5) (1) (2 2 2) (1) (2) (3 3 3 3 3) (4) (5) (6) (7))
Looks pretty good!
(equal (car tail) (car (last group))) seems equivalent to (equal (car tail) (car group))
To keep the elements in the original order, reverse the items of every group.
As you build the resulting list groups yourself, it's safe and more efficient to use nreverse instead of reverse.
There is no name clash when using list as parameter, instead of lst, as variables and functions live in different namespaces ("Lisp-2").
It's considered good style to give utility functions like this &key test key arguments so callers can decide on when list elements are considered equal (see e.g. Common lisp :KEY parameter use), to join the club of general functions like member, find and sort.
And a documentation string! :)
Updated version:
(defun identity-groups (list &key (test #'eql) (key #'identity))
"Collect adjacent items in LIST that are the same. Returns a list of lists."
(labels ((travel (tail group groups)
(cond ((endp tail) (mapcar #'nreverse (cons group groups)))
((funcall test
(funcall key (car tail))
(funcall key (car group)))
(travel (cdr tail) (cons (car tail) group) groups))
(t (travel (cdr tail) (list (car tail)) (cons group groups))))))
(nreverse (travel (cdr list) (list (car list)) nil))))
Tests:
(identity-groups '(1 2 2 2 3 3 3 4 3 2 2 1))
-> ((1) (2 2 2) (3 3 3) (4) (3) (2 2) (1))
;; Collect numbers in groups of even and odd:
(identity-groups '(1 3 4 6 8 9 11 13 14 15) :key #'oddp)
-> ((1 3) (4 6 8) (9 11 13) (14) (15))
;; Collect items that are EQ:
(identity-groups (list 1 1 2 2 (list "A") (list "A")) :test 'eq)
-> ((1 1) (2 2) (("A")) (("A")))
The desired function fits the pattern which consists in building a value G1 from a known subresult G0 and a new value, and can be implemented using REDUCE.
The first parameter of the anonymous reducing function is the accumulator, here a list of groups. The second parameter is the new value.
(reduce (lambda (groups value)
(let ((most-recent-group (first groups)))
(if (equal (first most-recent-group) value)
(list* (cons value most-recent-group) (rest groups))
(list* (list value) groups))))
'(1 3 5 4 4 4 4 5 1 2 2 2 1 2 3 3 3 3 3 4 5 6 7)
:initial-value ())
The result is:
((7) (6) (5) (4) (3 3 3 3 3) (2) (1) (2 2 2) (1) (5) (4 4 4 4) (5) (3) (1))
One problem in your code is the call to last to access the last group, which makes the code traverse lists again and again. Generally you should avoid treating lists as arrays, but use them as stacks (only manipualte the top elment).
If you need to reverse elements, you can use do it at the end of each group (order among equivalent values), or at the end of the whole function (order among groups).
A 'classical' recursive solution
(defun identity-groups (l &key (test #'eql))
(labels ((group (l last-group acc)
(cond ((null l) (cons last-group acc))
((and last-group (funcall test (car l) (car last-group)))
(group (cdr l) (cons (car l) last-group) acc))
(t
(group (cdr l) (list (car l)) (cons last-group acc))))))
(cdr (reverse (group l '() '())))))
Older version (requires an initial-value not equal to first list element)
So the version above got rid of this key argument.
(defun identity-groups (l &key (test #'eql) (initial-value '(0)))
(labels ((group (l last-group acc)
(cond ((null l) (cons last-group acc))
((funcall test (car l) (car last-group))
(group (cdr l) (cons (car l) last-group) acc))
(t
(group (cdr l) (list (car l)) (cons last-group acc))))))
(cdr (reverse (group l initial-value '())))))
Imperative-style looping construct
Tried for fun also a looping construct with do.
(defun group-identicals (l &key (test #'eql))
(let ((lx) (tmp) (res)) ;; initiate variables
(dolist (x l (reverse (cons tmp res))) ;; var list return/result-value
(cond ((or (null lx) (funcall test x lx)) ;; if first round or
(push x tmp) ;; if last x (lx) equal to current `x`,
(setf lx x)) ;; collect it in tmp and set lx to x
(t (push tmp res) ;; if x not equal to lastx, push tmp to result
(setf tmp (list x)) ;; and begin new tmp list with x
(setf lx x)))))) ;; and set last x value to current x
(cdr (reverse (group l initial-value '())))))
;; cdr removes initial last-group value
;; test:
(group-identicals '(1 2 3 3 4 4 4 4 5 5 6 3 3 3 3))
;; ((1) (2) (3 3) (4 4 4 4) (5 5) (6) (3 3 3 3))
(group-identicals '("a" "b" "b" "c" "d" "d" "d" "e") :test #'string=)
;; (("a") ("b" "b") ("c") ("d" "d" "d") ("e"))

Functions to print and replace elements in a list

I am trying to implement two functions : subterm and replace.
subterm takes two lists as arguments and prints the element in the first list that is reached after exhausting the second list.
For example, calling
(subterm '(1 2 (3 4 5) (6 (7 (8) 9 10))) '(4 2 2 1))
should return
8
I have come up with the following function which prints the nth element in the list :
(define (subterm list n)
(cond
((null? list) '())
((= n 1) (car list))
(else (subterm (cdr list) (- n 1)))))
replace takes 3 lists and returns the result of replacing the reached value with the rest of the list unchanged.
for example calling :
(replace '(1 2 (3 4 5) (6 (7 (8) 9 10))) '(11 12) '(4 2 2 1))
should return :
'(1 2 (3 4 5) (6 (7 ((11 12)) 9 10)))
Again, I came up with this code which replaces the nth element in the first list with the second list, leaving the rest of the first list unchanged :
#lang racket
(define (replace list elem n)
(cond
((empty? list) empty)
((eq? n 1) (cons elem (cdr list)))
(#t (cons (car list) (replace (cdr list) elem (- n 1))))))
How do I modify these functions to take in two lists?
Edit 1:
Some examples:
> (subterm '(1 2 3 4 5) '(3))
3
> (subterm '(1 2 3 4 5) '(2))
2
> (subterm '(1 2 (3 4 5) 6 7) '(3 2))
4
Consider this example:
> (subterm '(1 2 (3 4 5) (6 (7 (8) 9 10))) '(4 2 2 1))
8
In the above example, subterm takes 2 lists. Then it reads the second list. The second list basically tells subterm to return the 1st element (8) of the 2nd element ((8)) of the 2nd element (7 (8) 9 10) of the 4th element (6 (7 (8) 9 10) of the first list (1 2 (3 4 5) (6 (7 (8) 9 10))).
> (subterm '1 '())
1
> (subterm '(1 2 (3 4 5) (6 (7 (8) 9 10))) '())
'(1 2 (3 4 5) (6 (7 (8) 9 10)))
> (replace '(1 2 3 4 5) '(6 7 8) '(3))
'(1 2 (6 7 8) 4 5)
> (replace '(1 2 3 4 5) '(6 7 8) '(2))
'(1 (6 7 8) 3 4 5)
Consider this example:
> (replace '(1 2 (3 4 5) 6 7) '(8 9) '(3 2))
'(1 2 (3 (8 9) 5) 6 7)
replace takes in three lists: first list is the list in which elements have to be replaced. The second list contains the new elements which have to be put into the first list. The third list contains the positions where the elements have to be replaced.
So, it basically replaced the 2nd element (4) of the 3rd element (3 4 5) of the first list (1 2 (3 4 5) 6 7).
> (replace '(1 2 (3 4 5) (6 (7 (8) 9 10))) '(11 12) '(4 2 2 1))
'(1 2 (3 4 5) (6 (7 ((11 12)) 9 10)))
> (replace '(1 2 (3 4 5) (6 (7 (8) 9 10))) 1000 '(4 2 2 1))
'(1 2 (3 4 5) (6 (7 (1000) 9 10)))
> (replace '(1 2 (3 4 5) (6 (7 (8) 9 10))) 'x '())
'x
> (replace '1 '(2 3 4) '())
'(2 3 4)
First of all, you're using the name subterm for two different functions. Let's call the version you provided a code example for list-ref, and make the (car list) case happen when n = 0 instead of 1:
(define (list-ref list n)
(cond
((null? list) '())
((= n 0) (car list))
(else (list-ref (cdr list) (- n 1)))))
As it turns out, list-ref is already in the racket library, so you shouldn't really have to implement it in the first place. So using that, your subterm is trivial:
(define (subterm main-list path)
(match path
('() #f)
((list n) (list-ref main-list (sub1 n)))
((cons n rest) (subterm (list-ref main-list (sub1 n)) rest))))
I tried to code the replace procedure. With my knowledge I can say this is a hard one. However I managed to make it work at least with the example you gave. You could read it, try to understand it and then try to modify it to work with any other list. I believe you'll need an extra function to make it work properly.
#lang racket
(require racket/trace)
(define (replace list elem n)
(cond
((empty? list) empty)
((eq? n 1) (cons elem (cdr list)))
(#t (cons (car list) (replace (cdr list) elem (- n 1))))))
(define replace-with-lists
(λ (items replacement path res aux)
(letrec ([splits (list-split-at items (car path) '())])
(cond
((empty? (cdr path))
; (append
; (car (list-ref res 0))
; (list (append
; (car (list-ref res 1))
; (list (append (car aux)
; (replace (list-ref aux 1) replacement (car path))
; (list-ref aux 2)))))))
(let ([result (replace splits replacement 2)])
(replace aux
(append (car result)
(list (cadr result))
(caddr result)
)
2)))
(else
(replace-with-lists
(list-ref splits 1)
replacement
(cdr path)
(foldr cons (list (list
(list-ref splits 0)
(list-ref splits 2)))
res)
splits
)))
))
)
(define list-split-at
(λ (lst place res)
(cond
((empty? lst) res)
((= 1 place) (foldl cons
(list (cdr lst))
(foldr cons (list res) (list (car lst)))
))
(else
(list-split-at (cdr lst) (- place 1) (foldr cons (list (car lst)) res))
)
)))
(trace replace-with-lists)
Ok, I am in your programming languages class, and I am aware that this assignment is due tomorrow, so I don't want to help too much, or give you the answer. I will do my best to give you some hints in case you are still struggling. The following hints are for the replace function.
First, you need a base case. We are given this with the following
(replace '(1 2 (3 4 5) (6 (7 (8) 9 10))) 'x '())
'x
(replace '1 '(2 3 4) '())
'(2 3 4)
To do this, we just need a conditional statement that checks for an empty list. It is clear that if the last argument is an empty list, we need to "return" the second to last argument. (in your code this would be "elem" and "n")
Now comes the difficult part. It is really quite simply once you realize how many built in functions scheme/racket has. Here are the only ones I used, but they made solving the problem much much easier.
(append)
(list)
(take)
(drop)
(list-ref) //this one is more of a convenience than anything.
After the turn in date has passed, I will post my solution. Hope this helped.
EDIT: As this assignment was due a few minutes, I will post my solution as I don't think that would be considered cheating.
lang racket
(define (subterm term1 lat)
(cond
[(eqv? lat '()) term1]
[(eqv? (car lat)1) (subterm (car term1) (cdr lat))]
[else (subterm (cdr term1) (cons(-(car lat)1)(cdr lat)))])
)
(define (replace term1 term2 lat)
(cond
[(eqv? lat '()) term2]
[else (append(take term1 (-(car lat)1)) (list(replace (list-ref term1 (-(car lat)1)) term2 (cdr lat))) (drop term1 (car lat)))]))
​
Those are both functions.

Lisp - How can I check if a list is a dotted pair?

How can I check if a list in lisp is a dotted pair?
CL-USER 20 : 3 > (dotted-pair-p (cons 1 2))
T
CL-USER 20 : 3 > (dotted-pair-p '(1 2))
NIL
CL-USER 20 : 3 > (dotted-pair-p '(1 2 3))
NIL
I tried checking if length=2 but got error:
CL-USER 28 : 1 > (= (length (cons 2 3)) 2)
Error: In a call to LENGTH of (2 . 3), tail 3 is not a LIST.
A lisp list in "dotted pair notation" looks something like:
(1 . ()).
Since this is homework, I'll let you take this to the logical conclusion. Compare
(LIST 1 2) => (1 . (2 . ()))
with
(CONS 1 2) => (1 . 2).
What is different between these two? How can you tell the difference using predicates?
Remember all proper lisp lists end with the empty list. Ask yourself how do you access the second element of a cons pair? The solution from there ought to be clear.
Because a list always ends with the empty list, while a pair doesn't:
(listp (cdr '(1 2))) => T
(listp (cdr '(1 . 2))) => NIL
(not(listp(cdr (cons 1 2))))=> T
(not(listp(cdr (list 1 2))))=> nill
A dotted pair is a cons cell where it's CDR is not a cons itself (recursive definition). So this '(1 . 2) is a dotted pair, but this '(1 . ()) isn't, since it is just the printed representation of and the same as '(1).
(defun dotted-pair-p (x)
(and (consp x)
;; Check that CDR is not a list with LISTP
;; since (CONSP ()) ;;=> NIL
;; and the CDR of a pair can't be NIL for it
;; to be dotted.
(not (listp (cdr x)))))
(dotted-pair-p '(1 . 2)) ;T
(dotted-pair-p '(1 . ())) ;NIL
Dotted lists (lists whose last cons cell is dotted) are defined in Common Lisp by LIST*. We can now use the above function to define a predicate for them too:
(defun list*p (x)
(dotted-pair-p (last x)))
(list*p (list* 1 2 3 4)) ;T
(list*p (list 1 2 3 4)) ;NIL
You can check if a list is dotted (ends with a non-nil atom) with:
(defun dotted-listp (l)
(cond ((null l) nil)
((atom l) t)
(t (dotted-listp (cdr l)))))

Trying to remove duplicates of atoms specified in first list from second list

I'm trying to write a function that works like remove-duplicates, but it instead takes two lists as input, the first specifying characters for which duplication is not allowed, and the second being a list of various atoms which is to be pruned.
Currently I have this:
(defun like-remove-duplicates (lst1 lst2)
(if(member (first lst1) lst2)
(remove-if #'(lambda (a b)
(equals a b))lst1 lst2)))
I know it's not anywhere near right, but I can't figure out what I need to do to perform this function. I know I essentially need to check if the first item in list1 is in list2, and if so, remove its duplicates (but leave one) and then move onto the next item in the first list. I envisioned recursion, but it didn't turn out well. I've tried researching, but to no avail.
Any help?
CL-USER> (defun remove-duplicates-from-list (forbidden-list list)
(reduce (lambda (x y)
(let ((start (position y x)))
(if start
(remove y x :start (1+ start))
x)))
forbidden-list
:initial-value list))
REMOVE-DUPLICATES-FROM-LIST
CL-USER> (remove-duplicates-from-list '(1 2) '(1 2 1 3))
(1 2 3)
CL-USER> (remove-duplicates-from-list '(1 2) '(1 2 1 3 2))
(1 2 3)
CL-USER> (remove-duplicates-from-list '(1 2) '(1 2 1 3 2 4))
(1 2 3 4)
CL-USER> (remove-duplicates-from-list '(2 1) '(1 2 1 3 2 4))
(1 2 3 4)
CL-USER> (remove-duplicates-from-list '(2 1) '(0 1 2 1 3 2 4))
(0 1 2 3 4)
CL-USER> (remove-duplicates-from-list '(2 1) '(0 2 3 2 4))
(0 2 3 4)
CL-USER> (remove-duplicates-from-list '(2 1) '(0 2 2 3 4))
(0 2 3 4)
Recursion is performed by reduce (because here we have the most common recursion pattern: feed the result of previous iteration to the next) and removeing is done with the help of :start parameter, that is the offset after the first encounter (found by position) of the value being removed currently.
It's also important to account the case, when the value isn't found and position returns nil.
Something like this should work and have acceptable time-complexity (at the cost of soem space-complexity).
(defun like-remove-duplicates (only-once list)
"Remove all bar the first occurence of the elements in only-once from list."
(let ((only-once-table (make-hash-table))
(seen (make-hash-table)))
(loop for element in only-once
do (setf (gethash element only-once-table) t))
(loop for element in list
append (if (gethash element only-once-table)
(unless (gethash element seen)
(setf (gethash element seen) t)
(list element))
(list element)))))
This uses two state tables, both bounded by the size of the list of elements to include only once and should be roughly linear in the sum of the length of the two lists.
(defun remove-listed-dups (a b)
(reduce (lambda (x y) (if (and (find y a) (find y x)) x (cons y x)))
b :initial-value ()))