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.
Related
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.
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.
Hi i am learning Scheme new.I have question.Lets think I have defined a function which it adds element to list if it is empty.If there is an element in list and new element is added as second to list and goes like this.For example
>(add a) ; here list is empty
'(a)
>(add b) ; here a is in the list
'(a b)
>(add c) ; here a and b is in the list
(a b c)
List is updated like this.How can I write a function like this.I add elements to empty list each time with my code.I mean it is like that with mine.
>(add a)
'(a)
>(add b)
'(b)
>(add c)
'(c)
How can I write the proper code for this purpose ?
here is my code
#lang racket
(define addToList
(lambda (a b)
(cond ((null? a) b)
((null? b) a)
((cons (car a) (addToList (cdr a) b))))))
(addToList '(1 2 3) '())
You can't "add" to an empty list in any Lisp dialect, because in all Lisp dialects, the empty list is a special, immutable value.
In Racket, not only is the empty list immutable, but so are all lists. Code that manipulates lists needs to be written in "functional" style to work properly.
"Adding" to a list in the sense of your add function would mean creating a whole new list with one more element and then binding it to the same variable as before:
;;; This implementation of add would behave just like
;;; the examples at the top of your question.
(define add
(let ((the-list '()))
(lambda (new-item)
(set! the-list
(append the-list (list new-item)))
the-list)))
The above function runs slower the longer the-list is because it has to
copy every element before adding the new one. It is much faster to add to the beginning of a list instead of the end:
(define add
(let ((the-list '()))
(lambda (new-item)
(set! the-list
(cons new-item the-list))
the-list)))
For this reason, most Racket programs build their lists backwards, and then
use reverse as late as possible to create a forward version of the list.
Just like any other language there are two ways to mutate a value. You can mutate what a variable points to (binding) or you can mutate the targeted object by altering parts of the object. The last one requires that the object is not a primitive.
Using variable binding:
#!r6rs
(import (rnrs))
(define lst '())
(define (add element)
(set! lst (append lst (list element))) ; adding to front is much cheaper
lst)
Using mutation:
#!r6rs
(import (rnrs)
(rnrs mutable-pairs))
(define lst (list 'head))
(define tail lst) ; keep the last cons so we can add O(1)
(define (add element)
(set-cdr! tail (list element))
(set! tail (cdr tail))
(cdr lst))
Your procedure looks more like the functional kind since it's not actually mutating anything, but it would work if you kept the result you got back and fixed the fact that it's not extending the list but adding the element to the tail as a dotted list.
(define addToList
(lambda (a b)
(cond ((null? a) (list b)) ; result needs to be a list
((null? b) a)
((cons (car a) (addToList (cdr a) b))))))
(define lst '())
(set! lst (addToList lst 1))
(set! lst (addToList lst 2))
(set! lst (addToList lst 3))
lst ; ==> (1 2 3)
I would have written it like this to make it look more like scheme:
(define (add-to-end lst e)
(if (null? lst)
(list e)
(cons (car lst)
(add-to-end (cdr lst) e)))))
Of course adding to front is much cheaper and is done with plain old cons. If you add some elements and actually wanted to add it to end you get the same effect by reversing the list after adding your elements.
I have a circular list, eg: #0=(1 2 3 4 . #0#).
What I want to do is to insert a new element (x) into this list so that the outcome is #0=(x 1 2 3 4 . #0#). I have been trying using this code (x is the circular list):
(define (insert! elm)
(let ((temp x))
(set-car! x elm)
(set-cdr! x temp)))
However, I think that set-cdr! is not working like I want it to. What am I missing here? Maybe I am way off?
The easiest way to prepend an element to a list is to modify the car of the list, and set the cdr of the list to a new cons whose car is the original first element of the list and whose cdr is the original tail of the list:
(define (prepend! x list) ; list = (a . (b ...))
(set-cdr! list (cons (car list) (cdr list))) ; list = (a . (a . (b ...)))
(set-car! list x)) ; list = (x . (a . (b ...)))
(let ((l (list 1 2 3)))
(prepend! 'x l)
(display l))
;=> (x 1 2 3)
Now, that will still work with circular lists, because the cons cell (i.e., pair) that is the beginning of the list remains the same, so the "final" cdr will still point back to object that is the beginning. To test this, though, we need some functions to create and sample from circular lists, since they're not included in the language (as far as I know).
(define (make-circular list)
(let loop ((tail list))
(cond
((null? (cdr tail))
(set-cdr! tail list)
list)
(else
(loop (cdr tail))))))
(define (take n list)
(if (= n 0)
'()
(cons (car list)
(take (- n 1)
(cdr list)))))
(display (take 10 (make-circular (list 1 2 3))))
;=> (1 2 3 1 2 3 1 2 3 1)
Now we can check what happens if we prepend to a circular list:
(let ((l (make-circular (list 1 2 3))))
(prepend! 'x l)
(display (take 15 l)))
;=> (x 1 2 3 x 1 2 3 x 1 2 3 x 1 2)
Since you're trying to prepend an element to a circular list, you need to do two things:
Insert a new cons cell at the front of the list containing the additional element. This is easy because you can just perform a simple (cons elm x).
You also need to modify the recursive portion of the circular list to point at the newly created cons cell, otherwise the circular portion will only include the old parts of the list.
To perform the latter, you need a way to figure out where the "end" of the circular list is. This doesn't actually exist, since the list is, of course, circular, but it can be determined by performing an eq? check on each element of the list until it finds an element equal to the head of the list.
Creating a helper function to do this, a simple implementation of insert! would look like this:
(define (find-cdr v lst)
(if (eq? v (cdr lst)) lst
(find-cdr v (cdr lst))))
(define (insert! elm)
(set! x (cons elm x))
(set-cdr! (find-cdr (cdr x) (cdr x)) x))
I'm trying to create a function that will return the even numbered elements in a list.
For example:
(evens '(a b c d))
should return
(b d)
The code below seems to work for lists that have and odd numbers of elements, but if I give it a list with an even number of elements, it is incorrect.
For example:
(evens '(a b c d e))
will return
(b d)
But:
(evens '(a b c d))
will return
(a c)
Any thoughts?
Changed my code to:
(DEFINE (evens lis)
(cond
((null? lis) '())
(else (cons (cadr lis) (evens (cdr lis))))
))
Gets a error saying that the object passed to safe-car is not a pair?
The problem is that if your list has an even number of elements, the modulo branch is matched and you start consing with the car of the list ... hence in your example, you get the a, and so on.
More importantly, though, you don't need to use length for this function ... and you shouldn't: since length takes linear time in the length of the list, evens now takes quadratic time.
Suggestion: your program should 'remember' whether it's in an 'odd' or 'even' location at each recursive step ... how could you do this (there are several ways)?
Your code has few missing checks and a bit of incorrect logic.
(define (evens lis)
(cond
((null? lis) '())
((eq? (cdr lis) '()) '()) ;missing condition
(else (cons (cadr lis) (evens (cddr lis)))))) ; it is cddr not cdr
I'm going to answer your question with commented examples, in the hope that you actually learn something instead of just being given code that works. Actually, looking at several pieces of code may be more enlightening, assuming that you're new to scheme.
Your original definition looked like this:
(define (evens lis)
(cond (;; Check: Recursion stop condition
(null? lis)
'())
(;; Wrong: Calling length at each step => O(n^2)
;; Wrong: Assuming even element if list has even number of elements
(= (modulo (length lis) 2) 0)
;; Wrong: Recursing with the rest of the list, you'll get odds
(cons (car lis) (evens (cdr lis))))
(else
;; Wrong: Recursing with the rest of the list with cdr, you'll get odds
(evens (cdr lis)))))
Afterwards, you've edited your question to update it to something like this:
(define (evens lis)
(cond (;; Check: Recursion stop condition
(null? lis)
'())
(else
;; Check: Building list with second element
;; Wrong: If lis only has 1 element,
;; (cdr lis) is null and (car (cdr list)) is an error.
(cons (cadr lis)
;; Wrong: Recursing with cdr, you'll get odds
(evens (cdr lis))))))
A solution is to check if the list has at least a second element:
(define (evens lis)
(cond (;; Check: Recursion stop condition 1
(null? lis)
'())
(;; Check: Recursion stop condition 2: list of length = 1
(null? (cdr lis))
'())
(else
;; Check: Building list with second element
;; The previous cond clauses have already sorted out
;; that lis and (cdr lis) are not null.
(cons (cadr lis)
;; Check: Recurse "the rest of the rest" of lis with cddr
(evens (cddr lis)))))
Exercise: Use if and or to simplify this solution to only have 2 branches.
This same question has been asked time and again over the last couple of days. I'll give a direct answer this time, to set it straight:
(define (evens lst)
(if (or (null? lst) ; if the list is empty
(null? (cdr lst))) ; or the list has a single element
'() ; then return the empty list
(cons (cadr lst) ; otherwise `cons` the second element
(evens (cddr lst))))) ; and recursively advance two elements
And here's how to do some error checking first:
(define (find-evens lst)
(if (list? lst)
(evens lst)
(error "USAGE: (find-evens [LIST])")))