How do you use the Delete tool on Dr.Racket? - racket

Write a function my_delete that takes two parameters: an atom and a list (which may be a nested list). This function will produce a list, identical to its parameter list, except with all occurrences of an atom parameter removed, no matter how deep they were. The produced list should not have anything in place of the deleted atoms.
This is my code:
#lang racket
(define (delete atom list)
(cond
((empty? list) list)
((eq? atom (car list)) (delete atom (cdr list)))
(else (cons (car list) (delete atom (cdr list))))))
But I am getting nothing in return on DrRacket. Why is this? Thank you!!

Related

DrRacket - Display all the values in a list that are above average

I'm creating a function that consumes a list of numbers and produces the elements in the list that are above average.
Below is my code:
(define (listlength list)
(cond
((empty? list) 0)
(else (+ 1 (listlength (rest list))))))
(define (listsum list)
(cond
[(empty? list) 0]
[else (+ (first list)
(listsum (rest list)))]))
(define (average log)
(/ (listsum log) (+ (listlength log) 1)))
(define (average-filter log)
(cons
(cond
[(> (first log) (average log)) (first log)]
[else (average-filter (rest log))])))
So obviously there is something wrong with my code...Can someone help me?
The error message for (average-filter (cons 40 (cons 30 empty) is:
cons: expects 2 arguments, but found only 1
A couple of comments: in the average procedure, there's no need to add 1 to the denominator, but you should handle the case when it's zero. Also notice that you can improve your solution by calculating the average only once, it'll be the same for the input list, so you don't need to recalculate it at every iteration. And please don't call your parameters list or log, they will clash with existing procedures.
Now for the real issue with average-filter: it's the same error of your previous question, you must not put the cons part at the beginning, that's not how it works. You should call cons with the current element and the result of the recursive call, to build a list with the results. And you must have a base case, think about it: what would happen when you run out of elements to traverse? that's the point where you need to return an empty list:
(define (average-filter lst)
(cond
[(empty? lst) empty]
[(> (first lst) (average lst))
(cons (first lst) (average-filter (rest lst)))]
[else (average-filter (rest lst))]))
Please, spend some time studying the proper way to build an output list as a result of traversing an input list, notice that you need to:
Handle the case when the input list is empty.
cons the current element with the result of the recursive call, when it makes sense to do it.

LISP - atom after every occurrence of search atom

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.

Common Lisp: unable to get the uncompress function in Paul Graham's book working

Lisp newbie here.
I am reading Paul Graham's book, ANSI Common Lisp.
On page 38 is an uncompress function. It takes a list of pairs, where the first item in the pair is a number to indicate how many of the second item there should be. For example, uncompressing this:
((3 a) (2 b) c)
should produce this:
(A A A B B C)
I typed the uncompress function into a Lisp interpreter (GCL-2.6.2-ANSI) and then tested it like this:
(uncompress '((3 A) B (2 C) (5 D)))
That produced this error message:
Error in IF [or a callee]: Too many arguments.
Fast links are on: do (use-fast-links nil) for debugging
Broken at IF. Type :H for Help.
1 (Abort) Return to top level.
Below is the uncompress function. I think that I faithfully typed what was written in the book. I have tested each piece and each piece seems to work correctly. Truthfully, I'm stuck. I don't know what's causing the error. I'd appreciate your help.
(defun uncompress (lst)
(if (null lst)
nil
(let (elt (car lst))
(rest (uncompress (cdr lst))))
(if (consp elt)
(append (apply #'list-of elt)
rest)
(cons elt rest))))
(defun list-of (n elt)
(if (zerop n)
nil
(cons elt (list-of (- n 1) elt))))
If you use editor indentation tools, the code looks like this:
(defun uncompress (lst)
(if (null lst)
nil
(let (elt (car lst))
(rest (uncompress (cdr lst))))
(if (consp elt)
(append (apply #'list-of elt)
rest)
(cons elt rest))))
That would have made it easier to spot this error. Syntactically it is wrong, since the IF does not take more than three forms.
(defun uncompress (lst)
(if (null lst) ; the IF has four subforms, one too many
nil
(let (elt (car lst)) ;<- variables ELT and CAR? Makes no sense
(rest (uncompress (cdr lst)))) ; <- not using the result?
(if (consp elt) ; <- fourth form in IF? Does not make sense.
(append (apply #'list-of elt)
rest)
(cons elt rest))))
In Common Lisp both IF and LET are special operators with built-in syntax.
In Lisp the syntax for LET usually is:
let ({var | (var [init-form])}*) form* => result*
In Common Lisp it is possible to add declarations on top of the body forms of the LET:
let ({var | (var [init-form])}*) declaration* form* => result*
The syntax for IF in Common Lisp is:
if test-form then-form [else-form] => result*
Indentation
Generally it is not a good idea to manually indent Lisp code. Let the editor or IDE do it. Make sure that all code is properly indented.
If you have a syntax problem: first re-indent the expression -> this makes sure that the code is properly indented and then makes finding problems easier. Next compile the code and read the compiler error message. Common Lisp has great compilers and some have quite good error reporting.
The code
The code is not great anyway: it uses recursion where higher-order functions exist or a LOOP would be better
This version got both: the higher-order MAPCAN and a LOOP:
(defun uncompress (list)
(mapcan #'expand-item list))
(defun expand-item (item)
(typecase item
(atom (list item))
(cons (destructuring-bind (n element) item
(loop repeat n collect element)))))
You have the most typical common lisp syntax error: incorrect use of parentheses!
Here is the correct version:
(defun uncompress (lst)
(if (null lst)
nil
(let ((elt (car lst))
(rest (uncompress (cdr lst))))
(if (consp elt)
(append (apply #'list-of elt)
rest)
(cons elt rest)))))
Since these kind of errors are so common when no specialized editor is used, I advise you to use an editor like Emacs or Vim to edit your programs.

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.

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.