I am trying to replace a symbol in a list with another symbol example:
(replace 'the 'a '(the cat sat on the mat))
==> (a cat sat on a mat) So the "the" should be replaced by "a"
Here is my code,
(defun replace (item new-item list)
(cond ((null list)
list
)
((eq (first list) (item))
((rplaca list new-item)
(replace (rest list))))
))
;rplace replace the first of the cons with obj
;(defparameter *some-list* (list* 'one 'two 'three 'four)) => *some-list*
;*some-list* => (ONE TWO THREE . FOUR)
;(rplaca *some-list* 'uno) => (UNO TWO THREE . FOUR)
When I compile it in aligra is giving me the following error
Error: Function position must contain a symbol or lambda expression: (RPLACA LIST NEW-ITEM)
[condition type: PARSE-ERROR]
I don't understand why is giving this error since the rplace function takes two arguments.
There are several different errors in your code:
item is not a function, so that you should not surround it with parentheses
your recursive call should repeat the same two first arguments as the original call
the recursive call should be made in all cases (and not only when the car was replaced)
you have extra parentheses around the rplaca call, which are the actual cause of the reported error
(defun replace (item new-item list)
(cond ((null list)
list)
((eq (first list) item)
(rplaca list new-item)
(replace item new-item (rest list)))
(t
(replace item new-item (rest list)))))
(setq l '(a cat sat on a mat))
(replace 'a 'the l)
l ;; -> (the cat sat on the mat)
Also, as noted in comments, it is not customary to mute literals ; you might want to construct a new list instead, for example like this:
(defun replace-1 (item new-item list)
(mapcar (lambda (car)
(if (eq car item)
new-item
car))
list))
(replace-1 'a 'the '(a cat sat on a mat))
;; -> (the cat sat on the mat)
Related
I'm trying to create a function that would test whether the given list is circular with a re-starting point being the beginning of the list.
Expected results:
(setq liste '(a b c))
(rplacd (cddr liste) liste)
(circular liste) => t
(circular '(a b c a b c)) => nil
As I simply want to test if any subsequent item is 'eq' to the first one, I don't want to build the whole tortoise and hare algorithm.
Here is my code :
(defun circular (liste)
(let (beginningliste (car liste)))
(labels ( (circ2 (liste)
(cond
((atom liste) nil)
((eq (car liste) beginningliste) t)
(t (circ2 (cdr liste)))
) ) ) ) )
It doesn't give the expected result but I don't understand where my error is
I'm not sure I'm using 'labels' correctly
Is there a way to do that without using 'labels'?
Edit. I guess I have answered my third question as I think I have found a simpler way. Would this work?
(defun circular (liste)
(cond
((atom liste) nil)
((eq (car liste) (cadr liste)) t)
(t (circular (rplacd liste (cddr liste))))
)
)
First, the behavior is undefined when you mutate constant data: when you quote something (here the list), the Lisp environment has the right to treat it as a constant. See also this question for why defparameter or defvar is preferred over setq. And so...
(setq list '(a b c))
(rplacd (cddr list) list)
... would be better written as:
(defparameter *list* (copy-list '(a b c)))
(setf (cdr (last *list*)) *list*)
Second, your code is badly formatted and has bad naming conventions (please use dashes to separate words); here it is with a conventional layout, with the help of emacs:
(defun circularp (list)
(let (first (car list)))
(labels ((circ2 (list)
(cond
((atom list) nil)
((eq (car list) first) t)
(t (circ2 (cdr list))))))))
With that formatting, two things should be apparent:
The let contains no body forms: you define local variables and never use them; you could as well delete the let line.
Furthermore, the let is missing one pair of parenthesis: what you wrote defines a variable name first and another one named car, bound to list. I presume you want to define first as (car list).
You define a local circ2 function but never use it. I would expect the circularp function (the -p is for "predicate", like numberp, stringp) to call (circ2 (cdr list)). I prefer renaming circ2 as visit (or recurse), because it means something.
With the above corrections, that would be:
(defun circularp (list)
(let ((first (car list)))
(labels ((visit (list)
(cond
((atom list) nil)
((eq (car list) first) t)
(t (visit (cdr list))))))
(visit (cdr list)))))
However, if your list is not circular but contains the same element multiple times (like '(a a b)), you will report it as circular, because you inspect the data it holds instead of the structure only. Don't look into the CAR here:
(defun circularp (list)
(let ((first list))
(labels ((visit (list)
(cond
((atom list) nil)
((eq list first) t)
(t (visit (cdr list))))))
(visit (cdr list)))))
Also, the inner function is tail recursive but there is no guarantee that a Common Lisp implementation automatically eliminates tail calls (you should check with your implementation; most can do it on request). That means you risk allocating as many call stack frames as you have elements in the list, which is bad. Better use a loop directly:
(defun circularp (list)
(loop
for cursor on (cdr list)
while (consp cursor)
thereis (eq cursor list)))
Last, but not least: your approach is a very common one but fails when the list is not one big circular chain of cells, but merely contains a loop somewhere. Consider for example:
CL-USER> *list*
#1=(A B C . #1#)
CL-USER> (push 10 *list*)
(10 . #1=(A B C . #1#))
CL-USER> (push 20 *list*)
(20 10 . #1=(A B C . #1#))
(see that answer where I explain what #1= and #1# mean)
The lists with numbers in front exhibit circularity but you can't just use the first cons cell as a marker, because you will be looping forever inside the sublist that is circular. This is the kind or problems the Tortoise and Hare algorithm solves (there might be other techniques, the most common being storing visited elements in a hash table).
After your last edit, here is what I would do if I wanted to check for circularity, in a recursive fashion, without labels:
(defun circularp (list &optional seen)
(and (consp list)
(or (if (member list seen) t nil)
(circularp (cdr list) (cons list seen)))))
We keep track of all the visited cons cells in seen, which is optional and initialized to NIL (you could pass another value, but that can be seen as a feature).
Then, we say that a list is circular with respect to seen if it is a cons cell which either: (i) already exists in seen, or (ii) is such that its CDR is circular with respect to (cons list seen).
The only additional trick here is to ensure the result is a boolean, and not the return value of member (which is the sublist where the element being searched for is the first element): if your environment has *PRINT-CIRCLE* set to NIL and the list is actually circular, you don't want it to try printing the result.
Instead of (if (member list seen) t nil), you could also use:
(when (member list seen))
(position list seen)
and of course (not (not (member list seen)))
What I'm trying to do here is first flatten any given list and then pass that list into my encrypt function. Although this is not working and I'm not sure why.
Here is what I have so far,
(defun flatten (l)
(cond ((null l) l)
((atom l) (list l))
(t (loop for a in l appending (flatten a))))
)
(defun encrypt(enctext)
(flatten enctext)
(if(eq 'A (first enctext)) ;If the first charcater equals 'A'...
(progn ;To allow multiple statements in an if statement
(princ #\B) ; First statement, print this character
(encrypt(rest enctext)))) ;Second statement, run function again passing the rest of the characters
(if(eq 'B (first enctext))
(progn
(princ #\C)
(encrypt(rest enctext))))
)
And this is how i'm calling the encrypt function
(encrypt '((A)(B))
Should I call the "flatten" function within my "encrypt" function? Or call "encrypt" within the "flatten" function after the recursive calls?
And how would I properly pass the flattened list?
FLATTEN doesn't destructively modify the list. It creates a new list with the flattened contents. You have to use its return value instead of the original ENCTEXT. That is easily achieved by calling ENCRYPT like:
(encrypt (flatten '((A) (B))))
And removing the call to FLATTEN from ENCRYPT. Here's a somewhat cleaner version of your code:
(defun encrypt (enctext)
(unless (endp enctext)
(princ (ecase (first enctext) ; I'm assuming the input shouldn't
(A #\B) ; contain any symbols that aren't
(B #\C))) ; handled here. Otherwise use CASE
(encrypt (rest enctext)))) ; instead of ECASE.
If you want to do this without a separate function call to flatten the list, you'll need to recursively descend into the input list inside ENCRYPT. Something like:
(defun encrypt (enctext)
(unless (endp enctext)
(let ((first (first enctext)))
(if (atom first)
(princ (ecase first
(A #\B)
(B #\C)))
(encrypt first)))
(encrypt (rest enctext))))
(encrypt '((A) (B)))
; BC
Of course if you don't have a reason to want to do this using recursion for both depth and breadth, a loop would make the code much clearer:
(defun encrypt (enctext)
(dolist (el enctext)
(if (atom el)
(princ (ecase el
(A #\B)
(B #\C)))
(encrypt el))))
I am a beginner with lisp.
I manipulate list of list:
((name1, second) (name2, second2))
The goal of my function is to get the second element of the list that have name as it first node.
For example:
my list is: ((name1, second1) (name2, second2))
getelement list name1 should return second1.
(defun getelement (list name)
(if (eq list '())
(if (string= (caar list) name)
(car (car (cdr list)))
(getelement (cdr list) name)
)
()
)
)
But I get this error. I really don't understand what is happening with my code. I tried to put ' before expressions...
Error: The variable LIST is unbound.
Fast links are on: do (si::use-fast-links nil) for debugging
Error signalled by IF.
Backtrace: IF
The if clauses are in the wrong order.
When the string matches, you are taking the next element (cdr) instead of that matching element (car)
This should work:
(defun getelement (list name)
(if (eq list '()) ;end of list,...
'() ;return empty list
(if (string= (caar list) name) ;matches,
(car (car list)) ;take the matching element
(getelement (cdr list) name))))
(defun get-element (list name)
(cadr (assoc name list :test #'string=)))
(define list45 (map number->string(build-list 1000 values)))
list45
(first (list45))
(rest (list45))
ERROR:
application: not a procedure;
expected a procedure that can be applied to arguments
I am trying to iterate through the list that i converted to strings. to do that i tried to use the first and rest functions to view everything in the list. Why am i getting errors for this?
Thanks
Just drop the parentheses around the list:
(first list45)
=> "0"
(rest list45)
=> '("1" "2" … "998" "999")
In Scheme, when you surround something between (), the interpreter evaluates that as a function application with no arguments. Given that list45 is not a function, the "application: not a procedure" error is raised. In Racket is very easy to iterate over the list:
(for ([e (in-list list45)])
(displayln e))
But if for some reason you want to use first and rest to traverse the list, here's one possibility, using explicit recursion:
(define (iterate lst)
(unless (empty? lst)
(displayln (first lst))
(iterate (rest lst))))
(iterate list45)
I realize that a function can be referenced using #'PRINT to reference the PRINT function. If we have a list S where the first element is 'PRINT , can we reference this using #(car S) ?
Say I'm looking at a list where the elements in the list are atoms which are the names of some functions. Currently, I can do this:
(defun aritheval (S)
(funcall
(cond
((eq '+ (car S)) #'+)
((eq '- (car S)) #'-)
((eq '* (car S)) #'*)
((eq '/ (car S)) #'/)
)
'2
'3
)
)
This function would compute 2+3, 2-3, 2*3 or 2/3 depending on the first element in list S. S contains the names of these functions.
#(car S) makes no sense. The syntax exists but means a vector with symbols CAR and S.
use
(funcall (first somelist) someargument)
or
(apply (first somelist) a-list-of-arguments)
Your function is non-Lispy formatted.
Trailing parentheses are not used in proper Lisp code. You also don't need to quote numbers. Numbers are self-evaluating, they evaluate to themselves. Also we now may prefer FIRST over CAR and REST over CDR. The functions do the same, but the names are better. Whenever we deal with simple lists, FIRST, SECOND, THIRD, ... and REST are used.
(defun aritheval (S)
(funcall (cond ((eq '+ (car S)) #'+)
((eq '- (car S)) #'-)
((eq '* (car S)) #'*)
((eq '/ (car S)) #'/))
2 3)))
Since symbols can be used as names for global functions, above is not necessary.
This function below does the same, given the mapping from symbol to function is the same.
(defun aritheval (s)
(funcall (first s) 2 3)))