Lisp - Get rid of dotted list - list

I am building a function is Lisp ta reverses the first and last element of a list. I get that a list has a car and a cdr hence why there is a dot in my output. Is there a way to remove the dot?
(defun my-butlast (list)
(loop for l on list
while (cdr l)
collect (car l)))
(defun f-l-swap(list)
(append (last list)(cdr (my-butlast list))(car list))
)
(write(f-l-swap '(A B C D E)))
OUTPUT:
(E B C D . A)

append expects arguments to be lists. In your case (car list) is an atom. You have to change it to list if you want to stick with append. Ie:
(defun f-l-swap (list)
(append (last list)
(cdr (my-butlast list))
(list (car list))))

A list is a chain of cons pairs. eg. (1 2 3) is the visualization of (1 . (2 . (3 . ()))). In the event the last cdr is not () you have what we call a dotted list since then there is no simplified visualization of the last part. It has to be printed with a dot.
You have (E . (B . (C . (D . A)))) and want to have (E . (B . (C . (D . (A . ()))))). Do you see the difference? (car list) is not a list but one elment and that is why you get a dotted list.
Here are more sensible implementations of append and butlast:
(defun my-append (a b)
(if (null a)
b
(cons (car a) (my-append (cdr a) b))))
That only supports 2 arguments, but the idea for more is that it continues until you have consed all the previous lists and only have one left, which verbatim becomes the tail. Here is how that might look:
(defun my-append2 (x &rest xs)
(labels ((helper (x xs)
(cond ((null xs) x)
((null x) (helper (car xs) (cdr xs)))
(t (cons (car x) (helper (cdr x) xs))))))
(helper x xs)))
Here is butlast
(defun my-butlast (xs)
(if (null (cdr xs))
'()
(cons (car xs) (my-butlast (cdr xs)))))
Now, one should really do it with higher order functions or loop, but then you get the facts hidden how lists work. The code above shows you have they work.

Related

SICP/Scheme: Procedure that accepts a list of pairs and an element, returns a list of pairs

I'm having some issues with this problem I've been given. It's not homework, it's actually a problem I've encountered at a test and to deepen my understanding I would like to solve it successfully.
The problem is:
make a procedure element-count that takes a list of pairs "lst" and an element "el" and returns a list of pairs where, if the element "el" exists in "lst" as the first member, then the second member gets increased by 1. Otheriwse we add to the end of "lst" a pair (cons el 1).
The wanted output: element-count '((a 2)) b) -> '((a 2 (b 1))
This is what my code so far looks like:
#lang sicp
(define (append list1 list2)
(if (null? list1)
list2
(cons (car list1) (append (cdr list1) list2))))
(define (count-element lst el)
(cond ((eq? (car lst) el) (+ (cdr lst) 1))
(else (append lst (cons (el 1))))))
The first issue I'm having is that it tells me that "b" is undefined. Obviously, b doesn't need to be defined since I want it in my output. How should I fix this? The environment I'm working in is DrRacket.
The main question is how should I go about defining a list of pairs? Or is my code actually okay? Lists and pairs are still quite confusing to me so I apologize for silly questions.
You are pretty close to the correct solution; I think there is just some confusion about how lists and pairs are defined. Here's an implementation and usage of count-element that does what you want:
(define (count-element lst el)
(cond ((eq? (car lst) el) (+ (cdr lst) 1))
(else (append lst (list (cons el 1))))))
(count-element (list (cons 'a 2)) 'b)
There are two things to note.
First, the way to define a list of pairs is like this:
(list (cons 'a 1) (cons 'c 2))
or
'((a . 1) (c . 2))
Second, this is the correct way to use your append method:
(append lst (list (cons 'b 1)))
or
(append lst '((b . 1)))
That's because append is defined so that you pass in two lists, and it combines them into a single new list. That's why the second parameter is a list containing the pair you want to append.

Appending reversed list in Scheme

I am learning Scheme and wanted to write a recursive program that reverses a given list.
In one test case however, I noticed that a (b c) e -> e (b c) a.
What I'm trying to get is a (b c) e -> e (c b) a.
This is what I have:
(define (deep-reverse lst)
(if (null? lst)
'()
(begin
(display (car lst))
(display "\n")
(if (null? (cdr lst))
'()
(append (deep-reverse (cdr lst)) (list (reverse (car lst))))
) //End of inner if
))) //End of begin, outer if, define
When I attempt to run the code with
(deep-reverse '(1 (b c) (a b)))
I get:
1
(b c)
(a b)
mcdr: contract violation
expected: mpair?
given: 1
The issue is with (list (reverse (car lst))), although in an isolated test case it works fine. Which leads me to believe that the issue may have to do with append.
Thank you in advance.
Edit: Going from (list (reverse (car lst))) to (reverse (list(car lst))) makes the code run without an error but doesn't reverse (a b) to (b a).
As the error message explains, your problem is that you are trying to reverse a number. Firstly, let's remove some of the unnecessary conditions and debugging stuff in your program, arriving at this simpler program. Let's step through this program to see what's going on:
(define (deep-reverse lst)
(if (null? lst)
'()
(append (deep-reverse (cdr lst)) (list (reverse (car lst))))))
We start with
(deep-reverse '(1 (b c) (a b)))
Substituting the argument we get
(if (null? '(1 (b c) (a b)))
'()
(append (deep-reverse (cdr '(1 (b c) (a b))))
(list (reverse (car '(1 (b c) (a b)))))))
Because the condition is #f, this simplifies to
(append (deep-reverse (cdr '(1 (b c) (a b))))
(list (reverse (car '(1 (b c) (a b))))))
To evaluate the first argument, first find the cdr, and call deep-reverse on that. I will skip the steps here but you should easily be able to test that it works correctly.
(append '((b a) (c b)) (list (reverse (car '(1 (b c) (a b))))))
Next we evaluate the car:
(append '((b a) (c b)) (list (reverse 1)))
And here we see what the problem is: we can't reverse a single number!
The issue is that your deep-reverse should have two distinct behaviours recursively:
on a number, or symbol, or other non-list entity, don't do anything, because it does not make sense to reverse a number
on a list, deep reverse it
There are two reasons why your current program does not do this properly:
it only does a shallow reverse on the elements of the list; that is, it won't deep reverse '(((a b) (c d)) ((e f) (g h))) correctly
it fails if it ever encounters a number or other non-list, like a symbol
The easy fix is to add a condition to check if it's a pair? first before attempting to reverse it. If it's not pair?, then lst must either be nil (which we may leave as-is) or a non-list object (which we may also leave as-is)
(define (deep-reverse lst)
(if (pair? lst)
(append (deep-reverse (cdr lst)) (list (deep-reverse (car lst))))
lst))
Finally, I should note that the pattern we are using here is really a foldr pattern. We can abstract away this pattern with foldr:
(define (deep-reverse xs)
(cond ((pair? xs)
(foldr (lambda (x y) (append y (list (deep-reverse x)))) '() xs))
(else xs)))
But we note also that this is inefficient, because append is an expensive operation. Modifying the algorithm to a tail recursive one makes it clear that this is actually a foldl:
(define (deep-reverse xs)
(cond ((pair? xs)
(foldl (lambda (x y) (cons (deep-reverse x) y)) '() xs))
(else xs)))
which is how such a function might be written in typical idiomatic Scheme, or as pointed out by Will Ness,
(define (deep-reverse xs)
(cond ((pair? xs) (reverse (map deep-reverse xs)))
(else xs)))

Add or remove element in the middle of list (Scheme)

Is it possible to add or remove elements in the middle of a linked list in Scheme? I can't seem to think of a way doing this with car/cdr/cons, but I reccon there must be a way to this.
If I have a list '(1 3 5 6), and I need to put in 4 between 5 and 6 for example, is this doable?
Adding an element at a given position was done in a previous answer. Removing an element at a given position is similar:
(define (delete-at k lst)
(cond ((null? lst)
'())
((zero? k)
(cdr lst))
(else
(cons (car lst)
(delete-at (sub1 k) (cdr lst))))))
Here are two versions:
; list-insert : value index list -> list
; return list where the ith element is x
(define (list-insert x i xs)
(if (= i 0)
(cons x xs)
(cons (first xs) (list-insert x (- i 1) (rest xs)))))
(define (list-insert/version2 x i xs)
(define-values (before after) (split-at xs i))
(append before (list x) after))
(list-insert/version2 'x 2 '(a b c d))
(list-insert 'x 2 '(a b c d))
Both versions will allocate a new list. For large lists it will become inefficient.

Scheme function to reverse a list

For my programming languages class I'm supposed to write a function in Scheme to reverse a list without using the pre-made reverse function. So far what I got was
(define (reverseList lst)
(COND
((NULL? lst) '())
(ELSE (CONS (reverseList(CDR lst)) (CAR lst)))
))
The problem I'm having is that if I input a list, lets say (a b c) it gives me (((() . c) . b) . a).
How am I supposed to get a clean list without multiple sets of parenthesis and the .'s?
The problem with your implementation is that cons isn't receiving a list as its second parameter, so the answer you're building isn't a proper list, remember: a proper list is constructed by consing an element with a list, and the last list is empty.
One possible workaround for this is to use a helper function that builds the answer in an accumulator parameter, consing the elements in reverse - incidentally, this solution is tail recursive:
(define (reverse lst)
(reverse-helper lst '()))
(define (reverse-helper lst acc)
(if (null? lst)
acc
(reverse-helper (cdr lst) (cons (car lst) acc))))
(reverse '(1 2 3 4 5))
=> '(5 4 3 2 1)
You are half way there. The order of the elements in your result is correct, only the structure needs fixing.
What you want is to perform this transformation:
(((() . c) . b) . a) ; input
--------------------
(((() . c) . b) . a) () ; trans-
((() . c) . b) (a) ; for-
(() . c) (b a) ; mation
() (c b a) ; steps
--------------------
(c b a) ; result
This is easy to code. The car and cdr of the interim value are immediately available to us. At each step, the next interim-result is constructed by (cons (cdr interim-value) interim-result), and interim-result starts up as an empty list, because this is what we construct here - a list:
(define (transform-rev input)
(let step ( (interim-value input) ; initial set-up of
(interim-result '() ) ) ; the two loop variables
(if (null? interim-value)
interim-result ; return it in the end, or else
(step (car interim-value) ; go on with the next interim value
(cons ; and the next interim result
(... what goes here? ...)
interim-result )))))
interim-result serves as an accumulator. This is what's known as "accumulator technique". step represents a loop's step coded with "named-let" syntax.
So overall reverse is
(define (my-reverse lst)
(transform-rev
(reverseList lst)))
Can you tweak transform-rev so that it is able to accept the original list as an input, and thus skip the reverseList call? You only need to change the data-access parts, i.e. how you get the next interim value, and what you add into the interim result.
(define (my-reverse L)
(fold cons '() L)) ;;left fold
Step through the list and keep appending the car of the list to the recursive call.
(define (reverseList lst)
(COND
((NULL? lst) '())
(ELSE (APPEND (reverseList(CDR lst)) (LIST (CAR lst))))
))
Instead of using cons, try append
(define (reverseList lst)
(if (null? lst)
'()
(append (reverseList (cdr lst)) (list (car lst)) )
)
)
a sample run would be:
1]=> (reverseList '(a b c 1 2 + -))
>>> (- + 2 1 c b a)
car will give you just one symbol but cdr a list
Always make sure that you provide append with two lists.
If you don't give two lists to the cons it will give you dotted pair (a . b) rather than a list.
See Pairs and Lists for more information.

Scheme extract unique atoms from list

I'm trying to write a scheme function that will return the unique atoms found in the input list such that.
> (unique-atoms '(a (b) b ((c)) (a (b))))
(a c b)
> (unique-atoms '(a . a))
(a)
> (unique-atoms '())
()
I was thinking something like this as a start
(define (unique-atoms l)
(if (null? l)
'()
(eq? (car (l) unique-atoms(cdr (l))))))
but I don't know how to collect the atoms that are unique, and create a new list while checking everything recursively.
The following walks list, term by term. If the next value is a list itself, then a recursive call is made with (append next rest) - that is, as list is walked we are flattening sublists at the same time.
We use a (tail) recursive function, looking, to walk the list and to accumulate the rslt. We add to the result when next is not alreay in rslt.
(define (uniquely list)
(let looking ((rslt '()) (list list))
(if (null? list)
rslt
(let ((next (car list))
(rest (cdr list)))
(if (list? next)
(looking rslt (append next rest))
(looking (if (memq next rslt)
rslt
(cons next rslt))
rest))))))
> (uniquely '(a b (a b) ((((a))))))
(b a)
If you really want the code to work for 'improper lists' like '(a . a) then the predicates null? and list? probably need to change.
This problem has two parts:
You need to find a way to visit each element of the given form, recursing into sublists.
You need a way to collect the unique elements being visited.
Here's a solution to the first part:
(define (recursive-fold visitor initial x)
(let recur ((value initial)
(x x))
(cond ((null? x) value)
((pair? x) (recur (recur value (car x)) (cdr x)))
(else (visitor x value)))))
I leave it for you to implement the second part.
I found a half solution where the non unique items are removed, although this wont work for an atom b and a list with b such as '(b (b))
(define (uniqueAtoms l)
(cond ((null? l)
'())
((member (car l) (cdr l))
(uniqueAtoms (cdr l)))
(else
(cons (car l) (uniqueAtoms (cdr l))))))
The easiest way to solve this problem with all kinds of list structures is to divide it into two parts
1) flatten then list - this results in a proper list with no sublists
; if you use Racket, you can use the build-in flatten procedure
; otherwise this one should do
(define (flatten expr)
(let loop ((expr expr) (res '()))
(cond
((empty? expr) res)
((pair? expr) (append (flatten (car expr)) (flatten (cdr expr))))
(else (cons expr res)))))
2) find all unique members of this proper list
(define (unique-atoms lst)
(let loop ((lst (flatten lst)) (res '()))
(if (empty? lst)
(reverse res)
(let ((c (car lst)))
(loop (cdr lst) (if (member c res) res (cons c res)))))))
Tests:
; unit test - Racket specific
(module+ test
(require rackunit)
(check-equal? (unique-atoms '(a (b) b ((c)) (a (b)))) '(a b c))
(check-equal? (unique-atoms '(a (b) b ((c . q)) (a (b . d)))) '(a b c q d))
(check-equal? (unique-atoms '(a . a)) '(a))
(check-equal? (unique-atoms '(a b (a b) ((((a)))))) '(a b))
(check-equal? (unique-atoms '()) '()))