It is just really hard to understand from a standard description, so:
For instance, I'm trying to set a k-th position of some list (ls) to a specific value. Even have a function of my own, that gives acces to k-th elt.
(defun kth-elt (lst k)
(cond ((> 0 k) nil)
((equal 0 k) (car lst))
((< 0 k) (kth-elt (cdr lst) (- k 1))))).
Also made a function, that updates that value.
(defun kth-upd (lst k new)
(cond ((> 0 k) nil)
((equal 0 k) (setf (car lst) new))
((< 0 k) (kth-upd (cdr lst) (- k 1) new))))
Now i can actually use that, but i wanna understand the difference between it and DEFSETF. Also I still do not understand. how to "teach" defsetf to use these. Thx for help.
Based on your definitions, it is simply:
(defsetf kth-elt kth-upd)
Instead of using kth-upd, you can now use kth-elt and (setf kth-elt).
For example:
(let ((list (copy-list '(a b c d e f))))
(setf (kth-elt list 3) nil)
list)
=> (A B C NIL E F)
But the real benefits of using SETF consistently is that you can combine this setter with other ones. Just consider incrementing a value:
(let ((list (make-list 10 :initial-element 0)))
(incf (kth-elt list 3))
(incf (kth-elt list 5) 20)
list)
=> (0 0 0 1 0 20 0 0 0 0)
See also this answer from Rainer Joswig for more background on places and SETF.
Setf expander
Note that you are doing the list traversal twice: you first get the current value, then computes the new one; only then, you store the new value, starting from the beginning of the list:
0: (KTH-ELT (0 0 0 0 0 0 0 0 0 0) 3)
1: (KTH-ELT (0 0 0 0 0 0 0 0 0) 2)
2: (KTH-ELT (0 0 0 0 0 0 0 0) 1)
3: (KTH-ELT (0 0 0 0 0 0 0) 0)
3: KTH-ELT returned 0
2: KTH-ELT returned 0
1: KTH-ELT returned 0
0: KTH-ELT returned 0
0: (KTH-UPD (0 0 0 0 0 0 0 0 0 0) 3 1)
1: (KTH-UPD (0 0 0 0 0 0 0 0 0) 2 1)
2: (KTH-UPD (0 0 0 0 0 0 0 0) 1 1)
3: (KTH-UPD (0 0 0 0 0 0 0) 0 1)
3: KTH-UPD returned 1
2: KTH-UPD returned 1
1: KTH-UPD returned 1
0: KTH-UPD returned 1
This can also be seen by macroexpansion:
(incf (kth-elt list 3))
... is macroexpanded as:
(LET* ((#:LIST796 LIST) (#:NEW1 (+ 1 (KTH-ELT #:LIST796 3))))
(KTH-UPD #:LIST796 3 #:NEW1))
Another possible approach might be to use DEFINE-SETF-EXPANDER:
(define-setf-expander kth (list index)
(alexandria:with-gensyms (store cell)
(values `(,cell)
`((nthcdr ,index ,list))
`(,store)
`(setf (car ,cell) ,store)
`(car ,cell))))
The function returns 5 different code parts that can be assembled to access and modify a place. cell and store are local variables introduced using GENSYM.
The variable cell (i.e. the variable named after the fresh symbol bound to cell) will be bound to (nthcdr index list). store contains the value to set in the place. Here, it will be put at the appropriate place by using (setf (car cell) store). Also, the existing value in the place is (car cell). As you can see, we need to manipulate, under the hood, the cons cell we mutate (of course, an error is raised with empty lists).
The macroexpansion for (incf (kth list 3)) is:
(LET* ((#:CELL798 (NTHCDR 3 LIST)) (#:STORE797 (+ 1 (CAR #:CELL798))))
(SETF (CAR #:CELL798) #:STORE797))
The setter function knows how to access the place that holds the value we want to change, and can change it directly, which is more efficent than just a pair of reader/writer functions.
Remark about mutability
SETF is designed around mutable data. If you write an accessor for a key/value store on the network, so that (remote host key) will connect and retrieve a value, and (setf (remote host key) value) sends the new value back, then it is not guaranteed that the remote value is always updated when (remote host key) is used as an intermediate place.
For example, if the value is a list, (push val (remote host key)) will push on the local list created on your host, there is no obligation for setf to actually ensure the result is sent back to the network when it is part of a larger expression. That allows SETF to be efficient by mutating places, at the small cost of requiring you to be more explicit. In the preceding example, you have to write (setf (remote host key) new-list) directly (not as a nested place) to effectively send the new data back.
As an addendum to coredump's answer, it's worth noting that the following works, and is, in my opinion, much better than using defsetf:
(defun kth-elt (lst k)
(cond ((> 0 k) nil)
((= 0 k) (car lst))
((< 0 k) (kth-elt (cdr lst) (- k 1)))))
(defun (setf kth-elt) (new lst k)
(cond ((> 0 k) nil)
((= 0 k) (setf (car lst) new))
((< 0 k) (setf (kth-elt (cdr lst) (- k 1)) new))))
There are cases when you need defsetf but they are not that common.
(kth-elt itself is just a special-case of elt of course: in real life you don't need to write any of this.)
Related
This question already has answers here:
Why does an elisp local variable keep its value in this case?
(3 answers)
Closed 6 years ago.
I noticed that when I call the function fillBoard, it seems to work as it fills the list passed to it as I want, but it has a very weird side effect. Somehow once fillBoard is called, the clearBoard function will only return the list returned by fillBoard. Additionally if I call fillBoard again it will continue to update the value returned in clearBoard.
As far as I understand, there should be a new instance of the list variable in clear everytime its called, so I don't see how its being modified or how its storing a new value.
I am passing fillBoard an empty list like ((0 0 0 0) (0 0 0 0) (0 0 0 0) (0 0 0 0)), and it will return a list like ((1 2 3 0) (0 6 0 0) (0 0 0 0) (0 0 0 0)), which is then what clearBoard returns.
(defun fillBoard (list)
(let ((numVals (+ 4 (random 3)))
(rand 0)
(val1 0)
(val2 0))
(dotimes (x numVals)
(setf val1 (random 3))
(setf val2 (random 3))
(setf rand (nth val1 (nth val2 soln)))
(prin1 rand)
(write-line " ")
(if (= (nth val1 (nth val2 list)) 0)
(setf (nth val1 (nth val2 list)) rand)))
list))
(defun clearboard ()
(let (( list '((0 0 0 0) (0 0 0 0) (0 0 0 0) (0 0 0 0))))
list))
EDIT: I did seem to alleviate the issue by having clearBoard be passed a list then setting it directly to the blank board as opposed to a local variable, then returning that instead. However, I am still curious as to how what was happening in the original issue
EQness of your return result
Your function returns the same literal list all the time. It is data embedded into your code. Don't modify it.
CL-USER 4 > (eq (clearboard) (clearboard))
T
EQ returns T, because the first cons in both lists is actually the same cons.
Allocate fresh new lists
Use COPY-TREE inside clearboard to create a newly allocated list of lists, instead of returning the same literal list over and over:
(defun clearboard ()
(copy-tree '((0 0 0 0)
(0 0 0 0)
(0 0 0 0)
(0 0 0 0))))
CL-USER 5 > (eq (clearboard) (clearboard))
NIL
Don't modify literal data
Literal data here is a data list, which is embedded in your code. Don't modify your code.
The list returned by clearboard is defined as a constant structure. When you modify it in fillBoard, you are not modifying a copy, but the structure itself. Generate the board instead with
(loop repeat 4 collect (make-list 4 :initial-element 0))
I have a list of lists and want to test if all elements are different from each other, i.e. equal should return nil for all combinations of list elements.
E.g.
(defparameter feld '((1 0 0 5 5 0)
(0 0 0 0 0 0)
(1 1 5 5 0 0)
(0 1 0 1 5 5)
(5 5 1 0 1 0)
(1 0 1 0 5 5)))
I thought of using reduce but as far as I understand it only tests the equality of neighbors, as would do a loop construct like:
(loop for i below (length feld)
for j from 1
if (equal (nth i feld) (nth j feld)) return t)
Is there a simple way using a standard construct which I do not see at the moment or do I have to create a recursive function?
The whole data structure represents a "board game" where every list is a line on the board and each element in the inside-lists is a value of this very field. The three numerical values (0, 1 and 5) are something like empty, Symbol A and Symbol B. A valid board cannot have two identical lines. This is why I want to identify those.
Basically, it is like remove-duplicates without removing. In the meantime I was thinking about something like this:
(defun duplicates-p (lst)
(cond ((null lst) '())
((member (car lst) (cdr lst)) t)
(t (duplicates-p (rest lst)))))
Something like this:
(defun unique (lsts &aux (h (make-hash-table :test 'equal)))
(loop :for lst :in lsts
:never (gethash lst h)
:do (setf (gethash lst h) t)))
This procedure takes a non-negative integer n and creates a list of all lists of n 0's or 1's in the specific order required for a truth table. I am just trying to understand how the map portion of the procedure works. I am particularly confused as to how append, map, and the recursive call to all-lists are working together in the second argument of the if. Any help would be greatly greatly appreciated!
(define all-lists
(lambda (n)
(if (= n 0)
'(())
(append (map (lambda (k) (cons 0 k)) (all-lists (- n 1)))
(map (lambda (k) (cons 1 k)) (all-lists (- n 1)))
))))
The best strategy to understand a recursive function is to try it with the case sligthly more complex than the terminal one. So, let's try it with n=1.
In this case, the function becomes:
(append (map (lambda (k) (cons 0 k)) (all-lists 0))
(map (lambda (k) (cons 1 k)) (all-lists 0))
that is:
(append (map (lambda (k) (cons 0 k)) '(()))
(map (lambda (k) (cons 1 k)) '(())))
So, the first map applies the function (lambda (k) (cons 0 k)) to all the elements of the list '(())), which has only an element, '(), producing '((0)) (the list containing an element obtained by the cons of 0 and the empty list), and in the same way the second map produces '((1)).
These lists are appended together yielding the list '((0) (1)), in other words, the list of all the lists of length 1 with all the possible combinations of 0 and 1.
In the case of n=2, the recursive case is applied to '((0) (1)): so the first map puts a 0 before all the elements, obtaining '((0 0) (0 1)), while the second map produces '((1 0) (1 1)). If you append together these two lists, you obtain '((0 0) (0 1) (1 0) (1 1)), which is the list of all the possible combinations, of length 2, of 0 and 1.
And so on, and so on...
Actually, the function is not well defined, since it calculates unnecessarily the value of (all-lists (- n 1)) two times at each recursion, so doubling its work, which is already exponential. So it could be made much more efficient by computing that value only once, for instance in the following way:
(define all-lists
(lambda (n)
(if (= n 0)
'(())
(let ((a (all-lists (- n 1))))
(append (map (lambda (k) (cons 0 k)) a)
(map (lambda (k) (cons 1 k)) a))))))
Separating statements along with 'println' can help understand what is happening:
(define (all-lists n)
(if (= n 0)
'(())
(let* ((a (all-lists (- n 1)))
(ol1 (map (λ (k) (cons 0 k)) a))
(ol2 (map (λ (k) (cons 1 k)) a))
(ol (append ol1 ol2)))
(println "---------")
(println ol1)
(println ol2)
(println ol)
ol)))
(all-lists 3)
Output:
"---------"
'((0))
'((1))
'((0) (1))
"---------"
'((0 0) (0 1))
'((1 0) (1 1))
'((0 0) (0 1) (1 0) (1 1))
"---------"
'((0 0 0) (0 0 1) (0 1 0) (0 1 1))
'((1 0 0) (1 0 1) (1 1 0) (1 1 1))
'((0 0 0) (0 0 1) (0 1 0) (0 1 1) (1 0 0) (1 0 1) (1 1 0) (1 1 1))
'((0 0 0) (0 0 1) (0 1 0) (0 1 1) (1 0 0) (1 0 1) (1 1 0) (1 1 1))
One can clearly see how outlists (ol1, ol2 and combined ol) are changing at each step.
I'm attempting to create a function that creates copies of whatever list the user puts in by the desired number of copies.
User: (copy '(A) '(7))
Output: (A A A A A A A)
(defun copy (x y)
(cond ((-1 counter)
nil)
(T
(list (cons (car x) (cdr x)))
copy
(cdr x)))
I'm attempting to set up a counter and just create a new list into the current list by decrementing the counter. So far the counter is pseudo-code.
This is the counter I'm trying to figure out.
(defun count (y)
(let ((a y))
(- a 1)))
The error I get is that whatever I put into y isn't a number.
While I can understand why the first parameter is a list, the second must be a number. A very simple implementation might look like:
(defun copy (lst count)
(when (> count 0)
(append (copy-list lst) (copy lst (1- count)))))
Testing:
CL-USER> (copy '(A) 7)
(A A A A A A A)
CL-USER> (copy '(A B C) 7)
(A B C A B C A B C A B C A B C A B C A B C)
The usual caveats concerning the use of append and object copying apply.
I'd suggest passing your list as a &rest argument instead and use loop:
(defun repeat (n &rest items)
(loop repeat n append items))
Test
CL-USER> (repeat 10 0 1 2)
(0 1 2 0 1 2 0 1 2 0 1 2 0 1 2 0 1 2 0 1 2 0 1 2 0 1 2 0 1 2)
I am trying to create subsequences of some word with the following code. When I added by k, the code stopped responding, though if I replace k with a particular number, it works. What is happening?
(let ((c nil)) (loop for k from 0 to (length "abc")
finally (return c) do (loop for j from 0 to (length "abc") by k
do (loop for i from j to (length "abc") do (push (subseq "abc" j i) c)))))
Debugging
if I replace k with a particular number, it works
What happens if you replace k with 0?
It would be much more helpful if you formatted this code with typical conventions, and probably if you isolated the particular part of the code that's problematic. That is, (remove-duplicates …) isn't the problem here, you could have removed it. With some more conventional formatting, and some comments, your code is:
(remove-duplicates
(let ((c nil))
(loop for k from 0 to (length "abc") ; k starts at 0
finally (return c)
do (loop for j from 0 to (length "abc") by k ; looping for j from 0 to something by k
do (loop for i from j to (length "abc")
do (push (subseq "abc" j i) c)))))
:test 'equal)
What's going to happen if you try to loop for j from 0 to anything by k? You're pretty much saying, "start with j at 0, then increment it by 0 for the next iteration…" so j never gets anywhere. This really could have been caught with a print or format. I know that's not the same as using a debugger, but sometimes the simplest ways are the quickest:
[8]> (remove-duplicates
(let ((c nil))
(loop for k from 0 to (length "abc")
finally (return c)
do (loop for j from 0 to (length "abc") by k
do
(format t "~&k: ~a, j: ~a" k j )
(loop for i from j to (length "abc")
do (push (subseq "abc" j i) c)))))
:test 'equal)
k: 0, j: 0
k: 0, j: 0
k: 0, j: 0
…
Collecting subsequences
If you're trying to collect the subsequences of a given sequence, you might do it like this. This works on both strings (vectors) and lists (although it's less efficient for lists).
(defun subsequences (sequence)
(loop
with length = (length sequence)
for i from 0 to length
nconcing (loop
for j from (1+ i) to length
collecting (subseq sequence i j))))
(subsequences "abc")
;=> ("a" "ab" "abc" "b" "c")
(subsequences '(1 2 3))
;=> ((1) (1 2) (1 2 3) (2) (2 3) (3))
Appendex: A hard-to-understand error from SBCL
Interestingly, you'll get a runtime error with SBCL, although the error message doesn't make it particularly clear why. Perhaps it's related to the infinite looping.
* (remove-duplicates
(let ((c nil))
(loop for k from 0 to (length "abc")
finally (return c)
do (loop for j from 0 to (length "abc") by k
do
(loop for i from j to (length "abc")
do (push (subseq "abc" j i) c)))))
:test 'equal)
debugger invoked on a TYPE-ERROR in thread #<THREAD "initial thread" RUNNING
{1002978E71}>:
The value 0
is not of type
(OR (SINGLE-FLOAT (0.0)) (DOUBLE-FLOAT (0.0d0)) (RATIONAL (0))).
Type HELP for debugger help, or (SB-EXT:QUIT) to exit from SBCL.
restarts (invokable by number or by possibly-abbreviated name):
0: [ABORT] Exit debugger, returning to top level.
What do you think BY 0 should do in a loop?
(loop for i from 0 upto 10 by 0 do (princ '*))
If you are not advancing the variable, you'll get an endless loop.