I am experimenting with using substitute-if. Here I try to replace all values that are even in '((1) (2) (3) (4)) with '(0)
[9]> (substitute-if '(0) #'evenp '((1) (2) (3) (4)) :start 1 :key #'car)
((1) #1=(0) (3) #1#)
I am confused about the #1=(0) and #1 in the list. I expected it to return '((1) (0) (3) (0)).
Am I misunderstanding how substitute-if works or misunderstanding the representation of the list?
Am I misunderstanding how substitute-if works or misunderstanding the representation of the list?
Probably the latter.
#1=... marks a spot in the data structure and #1# refers back to it. The idea is to show that both elements refer to the same list. (See also http://www.lispworks.com/documentation/HyperSpec/Body/02_dhp.htm.)
It's like:
(let ((x '(0)))
(list '(1) x '(3) x))
Because they refer to the same object, if you were to modify the second list in place, the modification would also show up in the fourth list.
It seems like you have set the dynamic global variable *print-circle* to something truthy. If you evaluate *print-circle* you'll see it.
; make a list (1 1 1 1 1 ...)
(defparameter *test* (list 1))
(setf (cdr *test*) *test*)
(setf *print-circle* t)
(substitute-if '(0) #'evenp '((1) (2) (3) (4)) :start 1 :key #'car)
; ==> ((1) #1=(0) (3) #1#)
*test*
; ==> #1=(1 . #1#)
(setf *print-circle* nil)
(substitute-if '(0) #'evenp '((1) (2) (3) (4)) :start 1 :key #'car)
; ==> ((1) (0) (3) (0))
*test* ; never finishes
The last one will hang until it runs out of memory. be hurry to cancel it out or your system will surely be sluggish once it has used all your available memory and buffers and start getting the system to swap out other things.
This is why we have *print-circle*. The ability to see lists that are circular. The printed data structure is always the same so it's only how it is displayed which is different.
When you use substitute-if and replace with '(0) this has one address in memory and thus when *print-circle* is truthy it will only print it once and the other references will be shown as references since the system looks for the same object and not if it really is circular or not.
Related
I am familiar with how to set elements in a 2D array, which can be done using the following statement.
(setf (aref array2D 0 0) 3)
However, I am not familiar how to set elements in a list of lists, such as the following input: '((1) (2) (2) (1)). I can't use aref, since it only works on arrays.
As mentioned, while aref works on arrays, elt works on sequences which can be:
an ordered collection of elements
a vector or a list.
* (setf test-list '((1) (2) (2) (1)))
((1) (2) (2) (1))
* (setf (elt test-list 2) 'hi)
HI
* test-list
((1) (2) HI (1))
You can indeed use variables in place of fixed offsets:
* (setf test-list '((1) (2) (2) (1)))
((1) (2) (2) (1))
* (setf offset 2)
2
* (setf (elt test-list offset) 'hi)
HI
* test-list
((1) (2) HI (1))
To access the nth element of a list, there are (at least) two functions: nth and elt. The order of the parameters is different, and nth only work on lists while elt works on any sequence (i.e. lists, vector, strings ...):
(nth 1 '(foo bar baz)) => BAR
(nth 1 #(foo bar baz)) => ERROR
(elt '(foo bar baz) 1) => BAR
(elt #(foo bar baz) 1) => BAR
Now, in general, the way to set a value (as opposed to simply access it) is very straightforward, and at least for built-in functions this is almost always the case: whenever you have some form FORM which retrieves some value from what is called a place, the form (setf FORM <value>) will set this element to the given <value>. This works for functions such as car, cdr, gethash, aref, slot-value, symbol-function and many others, and any combination of those.
In your example, you have a list of lists. So, for example, to modify the "inner integer" in say the third list:
* (setf test-list '((0) (1) (2) (3))) ; changed the values to have something clearer
((0) (1) (2) (3))
* (car (nth 2 test-list)) ; this accesses the integer in the second list
2
* (setf (car (nth 2 test-list)) 12) ; this modifies it. Notice the syntax
12
* test-list
((0) (1) (12) (3))
On a side note, you should avoid modifying literal lists (created using the quote symbol '). If you want to modify lists, create them at runtime using the list function.
EDIT:
What happens is that setf knows, by "looking" at the form you give it, how to actually find the place that you want to modify, potentially using functions in this process.
If you look at other languages, such as Python, you also have some kind of duality in the syntax used both to get and to set values. Indeed, if you have a list L or a dictionary d, then L[index] and d[thing] will get the corresponding element while L[index] = 12 and d[thing] = "hello" will modify it.
However, in Python, those accessors use a special syntax, namely, the squares brackets []. Other types of objects use another syntax, for example, the dot notation to access slots/attributes of an object as in my-object.attr. A consequence is that the following code is invalid in Python:
>>> L = [1, 2, 3, 2, 1]
>>> max(L)
3
>>> max(L) = 12
Traceback (most recent call last):
File "<string>", line 9, in __PYTHON_EL_eval
File "/usr/lib/python3.8/ast.py", line 47, in parse
return compile(source, filename, mode, flags,
File "<string>", line 1
SyntaxError: cannot assign to function call
You have to write an other function, for example, setMax(L, val), to change the maximum of a list. This means that you now have to functions, and no symmetry anymore.
In Common Lisp, everything is (at least syntactically) a function call. This means that you can define new ways to access and modify things, for any function ! As a (bad) example of what you could do:
* (defun my-max (list)
(reduce #'max list))
MY-MAX
* (my-max '(1 2 3 8 4 5))
8
* (defun (setf my-max) (val list)
(do ((cur list (cdr cur))
(cur-max list (if (< (car cur-max) (car cur))
cur
cur-max)))
((endp (cdr cur)) (setf (car cur-max) val))))
(SETF MY-MAX)
* (setf test-list (list 0 4 5 2 3 8 6 3))
(0 4 5 2 3 8 6 3)
* (setf (my-max test-list) 42)
42
* test-list
(0 4 5 2 3 42 6 3)
This way, the syntax used to both set and get the maximum of a list is identical (FORM to get, (setf FORM val) to set), and combines automatically with every other "setter". No explicit pointers/references involved, it's just functions.
i would like to visit all the cons cells in a list and perform some action on them (including such things as setcar). is there an idiomatic way of doing this?
i can, i think, do something like this
(progn
(setq a (list 1 2 3 4 5 6))
(setq okay a)
(while okay
(if (eq (car okay) 3)
(setcar okay 22))
(setq okay (cdr okay))))
(where the if expression is my "application logic", say.)
but, if there's a terser way of doing this, i'd be interested in hearing about it.
If you want to mutate the cars of the list, then in recent emacsen the likely think you want is cl-mapl, which maps a function over successive tails of the list. This is essentially Common Lisp's mapl function: CL has
maplist which maps a function over tails and returns a new list of the values of the function, so (maplist (lambda (e) e) '(1 2 3)) is ((1 2 3) (2 3) (3));
mapl which is like maplist but returns the original list.
elisp (courtesy of some now-standard library) now has both cl-mapl and cl-maplist.
So:
> (let ((y (list 1 2 3 4 5 6 7)))
(cl-mapl (lambda (tail)
(rplaca tail 0))
y)
y)
(0 0 0 0 0 0 0)
or
> (let ((y (list 1 2 3 4 5 6 7)))
(cl-mapl (lambda (tail)
(rplaca tail (if (cdr tail) (cadr tail) 'fish)))
y)
y)
(2 3 4 5 6 7 fish)
(In neither of these cases do you need to make sure that y is returned: I just did it to make it clear that y is being destructively modified by this.)
(setq a (mapcar (lambda (x) (if (equal x 3) 22 x)) a))
That sets the value of variable a to the result of changing any members of a that are 3 to 22.
Choose the equality operator you want, equal, eql, or =, depending on whether you know that either all list members are numbers (use =) or you know that they are either numbers or you want to test object equality otherwise, (use eql), or you don't know what they might be (use equal).
You haven't indicated any need to do list-structure modification (setcar). It appears that all you care about is for a to be a list as I described.
I am bad at Lisp. Help me please to find a syntax error. I need to write a function which swaps two elements in list. This function must consist loop-cycle. Here is what if have so far.
(defun swap-two-element(z x y)
(let ((newlist nil) (newlist2 nil) (copyz z) (copyz2 z) (newx nil))
(loop
(when (= (- (length z) (length copyz2)) y)
(return (set newx car z)))
(setq newlist2 (append newlist2(car copyz2))
copyz2 (cdr copyz2)))))
Call example: (swap-two-element '(a b c d) 2 3)
Replace the word set with the word values and you are good to go.
PS. You need to address the warnings though, and explain what the function is supposed to do so that we could help you with the algorithm.
You really need to tidy up your question. The title says nothing, the code is badly formatted and you really need to play around with loop to get started. I won't give you your solution since you need to learn this by trying. Here is an example you can make use of to do your assignment.
;; this orders a list by their odd index
;; NB: index starts at zero so first element is even
(defun order-odd-index (list)
(loop :for element :in list ; iterates your list
:for index :from 0 ; starts from 0 and goes on
:if (oddp index) ; if in a loop
:collect element :into odd-list ; variable is automatically created
:else ; else in a loop
:collect element :into even-list
:finally (return (append odd-list even-list)))) ; what to do in the end
(order-odd-index '(4 67 3 2 7 9)) ; ==> (67 2 9 4 3 7)
I use keywords (like :for instead of for) to indicate what symbols are loop keywords and what are not. It's optional but I think it looks a lot cleaner.
Now your problem can be solved with collecting element into 5 variables. Two of them is when index is equal to one of the places (given as arguments) to be switched the other 3 are before, in between and greater. In the finally you can just append those variables in the correct order and you're done.
Say, we would like to use a function that requires a predicate, but for some reason we're interested in other features of the function (like :start and :end parameters), so we need to supply a predicate, that always returns true.
Obviously, it's not a problem at all:
CL-USER> (defparameter *list* '(0 1 2 3 4 5))
*LIST*
CL-USER> (remove-if (lambda (x) t) *list* :start 1 :end 3)
(0 3 4 5)
Works, but not beautifully at all. And we may get ugly message that variable x is not used. Since I'm in LISP for beauty, I'm curious if there is a 'always t' predicate?
We can define it:
(defun tp (&rest rest)
(declare (ignore rest))
t)
..but may be it exists?
You're looking for the function constantly that takes an argument and returns a function that always returns that value. The predicate you need, then is (constantly t). Thus:
CL-USER> (remove-if (constantly t) '(0 1 2 3 4 5) :start 1 :end 3)
(0 3 4 5)
The notes on constantly show that you were absolutely on the right track with your proposed implementation. (You did even better, though, by adding the (declare (ignore …)).)
Notes:
constantly could be defined by:
(defun constantly (object)
#'(lambda (&rest arguments) object))
After writing this, it occurred to me that this might be a duplicate. I didn't find a proper duplicate, found a similar, more specific, question that was looking to remove a single element at a position, Is there a common lisp macro for popping the nth element from a list?, in which Rainer Joswig's answer includes:
Removing the nth element of a list:
(defun remove-nth (list n)
(remove-if (constantly t) list :start n :end (1+ n)))
This is really just a generalization of that approach, since you're working with arbitrary sequence boundaries. Thus we could have (making the boundary argument analogous to subseq's):
(defun remove-subseq (sequence &optional (start 0) end)
(remove-if (constantly t) sequence :start start :end end))
(defun remove-nth (sequence n)
(remove-subseq sequence n (1+ n)))
CL-USER> (remove-subseq '(0 1 2 3 4 5) 1 3)
(0 3 4 5)
CL-USER> (remove-nth '(0 1 2 3 4 5) 3)
(0 1 2 4 5)
I'm writing a simple function that needs to remove a certain element from a list. The list has 3 lists inside, and I want to search the 2nd one for a given value. This 2nd list's elements are also lists (id x y).
My function receives a list and and id as arguments, and it has to remove the element from the second list that has that id.
(defun rem (list id)
(dolist (var (nth 1 list))
(cond (equal id (nth 0 var))
(delete var (nth 1 list))))
)
I search the second list of the given list, and when I find the element with id, I delete it. The problem is that I'm always getting NIL. I tried with function remove as well, but the result is the same.
There are a number of issues with this code, and describing them is actually longer than constructing a working example, so I'll show a working version first, and then walk through the code that you provided. Please read through that second section and be sure you understand the issues in the original code, though.
A working version
Based on your description, you want to remove each element of the second element of list whose first element is id. I'm not sure exactly what it is that you want to return, but assuming that it's like list, but with the new second element, you can do something like the following. I emphasized certain words in that paragraph, because they're important for solving this problem. You have an id, and you want to remove things from a sequence that have that id. You can do that with remove (or delete) by calling (remove id sequence :key <key>), where key is a function that extracts a value from the sequence elements to compare against id. You want to remove those elements from (second list) whose first is id. You'd use
(remove id (second list) :key 'first)
to do that. In context, you'd get a function like this:
(defun bex-remove (list id)
(list (first list)
(remove id (second list) :key 'first)
(third list)))
Here's an example:
(bex-remove '((1 2 3 4) ; values don't matter
((id-a x1 y1)
(id-b x2 y2)
(id-a x3 y3)
(id-b x4 y4))
(5 6 7 8)) ; values don't matter
'id-a)
;=> ((1 2 3 4) ((ID-B X2 Y2) (ID-B X4 Y4)) (5 6 7 8))
Issues with your code
There are a few issues:
You shouldn't try to define a function named rem.
You've got syntax errors in your code.
delete doesn't necessarily have the side effects that your code presupposes that it does.
dolist, by default, returns nil.
In more detail:
There's already a function named REM in the Common Lisp package that computes a remainder. Trying to evaluate your definition in SBCL signals an error:
Lock on package COMMON-LISP violated when setting fdefinition of
REM while in package COMMON-LISP-USER.
[Condition of type SYMBOL-PACKAGE-LOCKED-ERROR]
See also:
SBCL Manual, Package Locks [:node]
Common Lisp Hyperspec, 11.1.2.1.2 [:section]
You get a similar error in CLISP (with which you've tagged the question, so I assume it's the implementation that you're using):
[1]> (defun rem (x) x) ; not the same as your definition, but still a function named rem
** - Continuable Error
DEFUN/DEFMACRO(REM): #<PACKAGE COMMON-LISP> is locked
If you continue (by typing 'continue'): Ignore the lock and proceed
The following restarts are also available:
ABORT :R1 Abort main loop
We'll rename your function %rem so that we can continue, and we'll see what happens. When try compile the adjusted definition in SBCL, we get a warnings about undefined variables delete and equal.
; --> IF COND
; ==>
; (IF DELETE
; (PROGN VAR (NTH 1 LIST))
; NIL)
;
; caught WARNING:
; undefined variable: DELETE
; ==>
; (IF EQUAL
; (PROGN ID (NTH 0 VAR))
; (COND (DELETE VAR (NTH 1 LIST))))
;
; caught WARNING:
; undefined variable: EQUAL
;
; compilation unit finished
; Undefined variables:
; DELETE EQUAL
; caught 2 WARNING conditions
In CLISP you'll have to compile before you get similar warnings:
CL-USER> (defun %rem (list id)
(dolist (var (nth 1 list))
(cond (equal id (nth 0 var))
(delete var (nth 1 list))))
)
%REM
CL-USER> (compile '%rem)
WARNING: in %REM : EQUAL is neither declared nor bound,
it will be treated as if it were declared SPECIAL.
WARNING: in %REM : DELETE is neither declared nor bound,
it will be treated as if it were declared SPECIAL.
%REM
2
2
The syntax of cond is (cond (test expr*)*), which means that each test and its associated expressions need to be wrapped in parentheses. Updated to fix that, we now have:
(defun %rem (list id)
(dolist (var (nth 1 list))
(cond
((equal id (nth 0 var))
(delete var (nth 1 list))))))
When we compile that, we still get some warnings in SBCL, but CLISP doesn't generate similar warnings, even during compilation:
; in: DEFUN %REM
; (DELETE VAR (NTH 1 LIST))
;
; caught STYLE-WARNING:
; The return value of DELETE should not be discarded.
;
; caught STYLE-WARNING:
; The return value of DELETE should not be discarded.
;
; compilation unit finished
; caught 2 STYLE-WARNING conditions
What this is telling us is that you really need to save the results from delete. delete can modify a list in arbitrary ways, and yet isn't required to modify anything at all. For instance, in the following code, the value of the variable x isn't modified, although (delete 1 x) does return a list (2 3).
CL-USER> (let ((x (list 1 2 3)))
(delete 1 x) ; could return, e.g, (cdr x)
x)
;=> (1 2 3)
So what you're probably trying to write is:
(defun %rem (list id)
(dolist (var (nth 1 list))
(cond ; or (when (equal id (nth 0 var))
((equal id (nth 0 var)) ; (setf (nth 1 list) ...))
(setf (nth 1 list)
(delete var (nth 1 list)))))))
This code isn't likely to do much that's useful. One, you're modifying (nth 1 list) while you're iterating over it, which is unlikely to have good results. I'm not sure what the code is supposed to do, exactly. Since you're iterating over (nth 1 list), list must have the form
(<first-element> (var1 var2 ...) ...)
and since you take (nth 0 var), then each vari must also be a list, so list has the form
(<first-element> ((<elt10> ...) (<elt20> ...) ...) ...)
Regardless, your dolist will still return nil. The syntax for dolist is
dolist (var list-form [result-form]) declaration* {tag | statement}*
and that optional result-form defaults to nil. I'm not sure exactly what you want to return, but maybe it's list, in which case you'd do
(dolist (var list list)
…)
For instance:
(let ((list (list 1 2 3)))
(dolist (x list) ; return default (nil)
(+ x x)))
;=> NIL
(let ((list (list 1 2 3)))
(dolist (x list (reverse list)) ; return something
(+ x x)))
;=> (3 2 1)