LISP - atom after every occurrence of search atom - lisp

I am trying to add a new atom after the search atom in the list.
when I try to call the function appendConst recursively, I am getting the below error -
[1]> (defun appendConst (OLD NEW L)
(cond
((null L) ())
((EQ (car L) OLD) (appendConst (cons OLD (cons NEW (cdr L)))) )
(T (cons (car L) (appendConst OLD NEW (cdr L))))
))
APPENDCONST
[2]> (appendConst 'a 'd '(a c d e a m k))
*** - EVAL/APPLY: Too few arguments (1 instead of at least 3) given to APPENDCONST
The following restarts are available:
ABORT :R1 Abort main loop
Break 1 [3]>
Here, using my input, after every occurrence of 'a' I want to add a 'd' in the whole list given.
I am new to this, how to call the function recursively here?
TIA.

Your first recursive call (where you add NEW) does in fact have only the one argument that the error says it does. Just adding the missing OLD and NEW won’t work, since the recursive call would find OLD again. So just do the consing outside the call as in your other case:
(cons OLD (cons NEW (appendConst OLD NEW (cdr L))))
Note that neither case is tail-recursive: to avoid stack usage proportional to the length of the list, you’d have to modify the list in place or do something more complicated like passing the head and the tail of the new list when recursing.

Related

lisp last element functional form

Hey guys I need help with lisp function. I am supposed to create:
(myLast L)
Evaluates to the last element of list L.
eg. (myLast ‘(p a e g)) → g
I cant use all of the predefined forms for lisp only the ones we have been given in class:
(atom X)
(quote X)
‘X
(eq X Y)
(cons X L)
(car L)
(cdr L)
(list A B C)
(if X Y Z)
(cond (C1 S1) (C2 S2) …… (Cn Sn))
I thought I had it right when I put in:
(defun myLast (L)
(if ((eq L '()) (cdr L))
(car L)
(myLast (cdr L))))
However I am getting an error:
Error: The variable MYHW4.LISP is unbound.
Error signalled by EVAL
Backtrace: EVAL
Broken at SYSTEM::GCL-TOP-LEVEL.
I am completely new to LISP and trying to complete this assignment. I was hoping you guys could help me out and let me know why I am getting this error, and is my logic for the last functional form correct? Thanks!
There are multiple problems with your code.
You have excess parentheses. ((eq L '()) is not allowed as the only expression allowed at operator position is an anonymous function.
Your if only have a consequence expression but not a alternative. It isn't the last expression so it's dead code.
The you do car, also not in real position so far code also.
Tail expression is the recursion and is done unconditionally. It's called infinite recursion.
I think perhaps you meant something like this:
(defun myLast (list)
(if (null (cdr list))
(car list)
(myLast (cdr list))))
The error message is unrelated to your code. You probably typed (load myhw4.lisp) without quotes in which case your Lisp rightly think that you wanted to take the value bound to the variable myhw4.lisp, which does not exist. You need to quote strings "like so".
Also, ((eq L '()) ...) is problematic, since the first form is (eq ...) which is not a function or a lambda. That will signal an error..
The above makes your code wrong, but you are not far from it.

Why does this LISP code emit periods or complain that lists must not end in 4?

I just started learning LISP today just for the heck of it, so I am completely new to it. I do have experience in other languages though. I tried to write a function that returns a list exactly as is, except without the last element.
While I intend to rewrite this function anyway since I'm sure there's a simpler way of doing it, my version produced some very unusual output. For the record, I'm using the CLISP environment.
(defun my-butlast (L)
(if (null (rest L))
nil
(if (eq nil (my-butlast (rest L)))
(first L)
(cons (first L) (my-butlast (rest L)))
)
)
)
(my-butlast '(1 2 3 4 5))
This produced the output (1 2 3 . 4)
And so my question is, where did the point come from?
Also, if I try to run (length (my-butlast '(1 2 3 4))) I get a mystifying error: A proper list must not end with 4. What does that mean?
. is used in the representation of a cons whose cdr is not NIL. E.g.
(cons 1 2)
is displayed as
(1 . 2)
Consider what happens in your function if you do
(my-butlast '(1 2))
The test (eq nil (my-butlast (rest L)) will be true, so it returns (first L). Notice that this is just the number 1, not a list containing 1. You need to change to:
(if (eq nil (my-butlast (rest L)))
(list (first L))
(cons (first L) (my-butlast (rest L)))
)
Incidentally, it's more idiomatic to write (null (my-butlast (rest L))).
Try doing I believe for your base case (it's been a while since I wrote lisp):
(list (first L))
(first L) will not return a list and cons of one element to another will create the structure you are looking at. Essentially your linked list is ending in [3|4] instead of [3|->] [4|0] with my lame ascii box diagrams.

Finding duplicate atoms in possibly nested lists in LISP

I am trying to figure out how to find duplicate atom in possibly nested lists. I have been trying to figure this out all day. If you could please give me the logic, that would be great because I really want to learn.
basically
(findDup '(a b b)) would return t
(findDup '(a c ((d (f a)) s))) would also return t
The easiest and most efficient way would be the following (pseudocode):
Create a data structure (such as Common Lisp's hash table) to remembering which atoms were seen
Create a recursive sub-function that does the actual traversing - walking the nested lists and adding all new atoms to the data structure, and if one is already there, returning true
If the list is sorted or can be sorted, this is a simple solution:
(defun find-duplicates (lst)
(let ((dup-list nil))
(sort lst)
(mapcon (lambda (l) (when (eq (car l) (cadr l)) (push (car l) dup-list))) lst)
dup-list ))
This should take care of the first case:
(defun find-duplicates (lst)
(let ((h (make-hash-table))
(dupes))
(mapcar #'(lambda (x)
(if (gethash x h)
(push x dupes)
(setf (gethash x h) t)))
lst)
dupes))
If the list is empty/without an atomic car however deeply you go (e.g. (car (car (car ...))) recursively), then the answer is false.
You want to find the first atom of the list, and see if that atom occurs anywhere else in the list. You can do that with a function like member-of?—something similar is discussed in The Little Schemer, but basically you just test all the atoms in the list, and recur on lists, against that atom.
Then if that atom is in the list, you can return true.
Else, you'll try again (recur on) with the cdr of the list.
I'd start with a wrapper function that creates a hash table and passes the hash table and the list to a second function (alternatively, use a &optional argument, if you're using Common Lisp).
Then, the following pseudo-code should be enough:
If we're looking at an empty list, there are no duplicates
If the head is a list, we can return the logical OR of "inspect the head" and "inspect the tail"
If the head is an atom, it's a duplicate if it's already in the hash table. If not, add it to the hash table and inspect the tail for duplicates.

Get Last Element of each list

Let us say I have a list ((3 4 5) (d e f) (h i j) (5 5 5 5))
How can I get the last element of each list in such a way that the output would look like this (5 f j 5)?
Assuming this is about Common Lisp, there is a function last which returns a list containing the last item of a list. If you use this function with mapcan, which applies a given function to each element of a list and returns the concatenated results, you'll get what you want.
Note though that accessing the last element of a list is an O(N) operation, so if this isn't just homework after all, you might want to consider if you can't solve the real problem more efficiently than taking the last item of each list (maybe use another datastructure instead).
This, like most early LISPy homework problems is an exercise in thinking recursively and/or thinking in terms of induction. The way to start is to ask yourself simple questions that you can answer easily.
For example, if you had been asked to write something that gave you the first element in each list, I would thing about it this way:
Given a list of lists:
What is first-element of every list in the list '()? (easy - null)
What is first-element of every list in the list '(a)? (easy - a, or maybe an error)
What is first-element of every list in the list '((a))? (easy - (a))
What is first-element of any list in the form '(anything), where anything is a list? (easy - (first anything))
What is the first element of every list in the form '(anything morestuff)? (easy - (cons (first anything) (first-element morestuff)) )
What is first of an atom? either the atom or an error (depends on your point of view)
What is first of null? nil.
What is first of a list? (car list)
From here we can start writing code:
;; here's first, meeting questions 6-8
(define first (lambda (l)
(cond
((null? l) nil) ; Q7
((atom? l) l) ; Q6
(t (car l))))) ; Q8
;; with first we can write first-element, meeting questions 1-5
(define first-element (lambda (l)
(cond
((null? l) nil) ; Q1
((atom? l) (first l)) ; Q2
(t (cons (first (car l) (first-element (cdr l)))))))) ; Q4-5
Now this isn't your homework (intentionally). You should play with this and understand how it works. Your next goal should be to find out how this differs from your assignment and how to get there.
With respect to MAPCAR? Don't worry about it. You need to learn how to solve recursive problems first. Then you can worry about MAPCAR. What is the point of this assignment? To help you learn to think in this mode. Dang near everything in LISP/Scheme is solved by thinking this way.
The reason I went with all the questions to break it down into the parts that I'm worried about. If I'm given the task "how do I do foo on every item in a list?" I should answer the questions: How do I do handle null? How do handle an atom? How do I do handle on the first element on the list? How do I handle everything else? Once I've answered that, then I figure out how to actually do foo. How do I do foo on null? How do I do foo on an atom? How do I do foo on a list?
(defun get-last-lists (s)
(setq rt 'nil)
(loop for i from 0 to (- (length s) 1)
do (setq rt (append rt (last (nth i s)))))
(print rt))
as a beginner of lisp, i post my solution.
Write a procedure that returns the last element of a list, then learn a little about the built-in MAP (a.k.a. MAPCAR) procedure and see if any lightbulbs go off.
probably it is already solved, but I figured this out
; SELECT-FROM-INNER-LIST :: [list] -> [list]
(DEFUN SFIL (lst)
(COND ((NULL lst) NIL)
((LISTP (FIRST lst)) (APPEND (LAST (FIRST lst)) (SFIL (REST lst))))
))
Now, this works for legit list...so if you call function SFIL with correct list.... if not, it will return NIL
hopefully this will be helpful, for anyone who finds it

Homework: Lisp items that appear more than once in a list

Given a list, I'm trying to return a new one that has only the items that appear more than once in the first list I receive as a parameter.
I have done the following:
(defun myf (lista)
(if (endp lista)
nil
(if (member (first lista) (rest lista))
(append (list (first lista)) (myf (rest lista)))
(myf (rest lista)))))
If I run the following: (myf '(A A B A B C)), it returns (A A B).
How can I make it return items only once (i.e., not have double "A")?
Once you've found that a letter is in the list more than once, you don't need to check it again, so you don't need it in the rest of the list. So you could modify the remaining list...
Note: this answer intentionally somewhat vague, since it's for homework and all. :)
The problem seems to be that you are checking to see if the first element of the list is in the tail of the list and appending it to the result list. The problem comes up when you come to the second instance of A, which when checked says yes it is in the tail because there is a 3rd instance of A in the list. If the input list had 4 A's then it would return 3 of them.
So to solve this need to check if A is already a member of the result list. That is, if first lista is not a member of list then append first lista to list.
Vincent, Gishu and Jerry hinted that you need to check if the item is already in the result list before appending to it, while Derek hinted that you could modify the original list when you see that an item is repeated.
Read the documentation of the functions adjoin and remove here:
http://www.lispworks.com/documentation/HyperSpec/Body/f_adjoin.htm
http://www.lispworks.com/documentation/HyperSpec/Body/f_rm_rm.htm
The HyperSpec is a very useful reference, add it your bookmarks.
Those two functions do not modify their arguments, but instead return the result as a new list. There are other functions that DO modify their arguments and thus might be more efficient, but at this point perhaps you shouldn't worry about them.
OK, I hope that by the time I have written this you have figured it out. If not, keep trying, that's the only way you'll really learn.
Now I'd like to talk to you about another approach, and that is about carrying the result through the recursive calls.
Our function repeated will do nothing but call a helper function repeatedr which will do the actual work, passing to it an initial empty result '():
(defun repeated (lst)
(repeatedr lst '()))
Now let's define the helper function, it receives two parameters: the list to search for duplicates, and the result list where we will accumulate the duplicate items.
(defun repeatedr (lst result)
(if (null lst)
result
(if (member (first lst) (rest lst))
(repeatedr (rest lst) (adjoin (first lst) result))
(repeatedr (rest lst) result))))
When the condition (member (first lst) (rest lst)) holds true we will adjoin the first item to the result, and the result of that adjoining will be passed to the recursive call as the second parameter; otherwise we just pass the result as is to the recursive call.
When the list is finally empty (if (null lst) we will return the result.
> (repeated '(a a b a b c))
(B A)
Notice that the result is (B A) and maybe you were expecting it to be (A B). Try to follow the execution of the recursive calls and the values of the parameters at each call with pen and paper, that will be a good exercise, and you'll have to play with adjoin to understand its behaviour. If you want to get the result reversed you can modify the function like this:
(defun repeatedr (lst result)
(if (null lst)
(reverse result)
(if (member (first lst) (rest lst))
(repeatedr (rest lst) (adjoin (first lst) result))
(repeatedr (rest lst) result))))
This reverses the result when the recursion finishes.
Now, what about the suggestion of removing the duplicate elements from the list before going forward? We could have written our function like this:
(defun repeatedr (lst result)
(if (null lst)
result
(if (member (first lst) (rest lst))
(repeatedr (remove (first lst) lst) (cons (first lst) result))
(repeatedr (rest lst) result))))
Try to play with remove at the REPL:
> (remove 'a '(a b c d a e f b a d))
(B C D E F B D)
Notice that we are no longer adjoining to the result, instead we just create a new "cons cell" with (cons (first lst) result). cons and adjoin do the same thing, except that adjoin will add the value only if it is not already present in the list.
Hope this gives you something to play with.
The problem seems to be that you're not checking if the element exists in the output list before appending to it.
Right now, for each element in the list, you're adding that element to the result if its not contained in the remainder of the list.
To get the result you apparently want, you'd add each element in the list to the result if it's not yet contained in the result.
If order is not a concern then you can also do:
(defun my-fun-no-order (lst)
(loop for (item . rest) on lst
when (= (count item rest) 0)
collect item))
Here we iterate over a list spitting it into the current item being iterated over and the rest of the items yet to be examined. The when clause determines the situation under which we collect the item.