I have some code that is supposed to take a list and return the reverse of that list. However, it just returns the list. Here is the code
(define (reverse listx)
(define (thing list1 list2)
(if (null? list1)
list2
(thing (cdr list1) (append list2 (list (car list1))))
)
)
(thing listx nil)
)
The problem I think hinges on the fact that
(append nil 1) => 1
rather than
(append nil 1) => (1)
No, that's not it: you do call (append list2 (list ...)), with the 2nd arg enclosed in a list.
The problem is that you use append while you ought to use simple cons there: (thing (cdr list1) (cons (car list1) list2)).
With cons, each new element from list1 will go on top (i.e. "to the left of") the previously handled ones, hence building the result in reverse:
(a b c d e)
--------------------------
(a b c d e) ()
(b c d e) (a)
(c d e) (b a)
(d e) (c b a)
(e) (d c b a)
() (e d c b a)
--------------------------
(e d c b a)
But with append you're just recreating the same list.
Related
I would like to return the nth cdr of a list. For example, I say
(nth-cdr 3 '(a b c d e)) and i would get (c d e) as output. I am not sure where I am going wrong with my code.
My approach is this. I will check if (= num 0) if it is, I will return the list. If not, I will recursively call nth-cdr and subtract 1 from num and cdr list
The code is this
(define arbitrary-cdr (lambda (num list)
(if (= num 0)
'()
(arbitrary-cdr (- num 1) (cdr list))
)))
However, I get this error when i try doing (arbitrary-cdr 3 ā(a b c d e))
ā: undefined;
cannot reference an identifier before its definition
I am not sure what this means. When I say that, it means I hit the base case and would just like to return the list. I think my logic is correct though.
The first code that you posted was:
(define arbitrary-cdr
(lambda (num list)
(if (= num 0)
(list)
(arbitrary-cdr (- num 1) (cdr list)))))
The error that you received was:
scratch.rkt> (arbitrary-cdr 3 '(a b d c e))
; application: not a procedure;
; expected a procedure that can be applied to arguments
; given: '(c e)
The problem was that you used list as an argument to the arbitrary-cdr procedure; since Racket is a lisp-1, procedures do not have their own namespace, so this redefined list. With (list), and with list redefined the code attempted to call ((c e)), but (c e) is not a procedure.
This is a great example for why you should not use list or other built-in procedure identifiers as parameters in your own procedure definitions in Scheme or Racket. You can get away with this in Common Lisp, because Common Lisp is a lisp-2, i.e., has a separate namespace for functions.
With your updated code:
(define arbitrary-cdr
(lambda (num list)
(if (= num 0)
'()
(arbitrary-cdr (- num 1) (cdr list)))))
I don't get the error you report; maybe your code is not quite what you have posted. But, there is a mistake in the logic of your code. As it is, an empty list will always be returned:
scratch.rkt> (arbitrary-cdr 3 '(a b c d e f))
'()
The problem is that when the base case is reached you should return the input list, not an empty list. That is, given (arbitrary-cdr 0 '(a b c)), you want the result to be (a b c). This also means that your test case is wrong; (arbitrary-cdr 0 '(a b c d e)) --> '(a b c d e), and (arbitrary-cdr 3 '(a b c d e)) --> '(d e).
Here is your code rewritten, using xs instead of list to avoid the redefinition, and returning xs instead of an empty list when the base case is reached:
(define arbitrary-cdr
(lambda (num xs)
(if (= num 0)
xs
(arbitrary-cdr (- num 1) (cdr xs)))))
Sample interactions:
scratch.rkt> (arbitrary-cdr 0 '(a b c d e))
'(a b c d e)
scratch.rkt> (arbitrary-cdr 1 '(a b c d e))
'(b c d e)
scratch.rkt> (arbitrary-cdr 3 '(a b c d e))
'(d e)
Given a list of lists as an input, I want to execute a procedure such that the final result would be:
(define (thing . lists) ; list of lists (l1 l2 ... lN)
;returns ...f(f(f(l1 l2) l3) lN)...
)
So for example:
(thing '(a b) '(c d) '(e f))
...would result in f(f((a b) (c d)) (e f))
I am fighting with folding, lambda, apply and map, but I can't figure out right way.
Assuming that the input has at least two lists and that f was previously defined:
(define (thing . lists)
(foldr (lambda (lst acc)
(f acc lst))
(f (car lists) (cadr lists))
(cddr lists)))
For example:
(define f append)
(thing '(a b) '(c d) '(e f))
=> '(a b c d e f)
I'm trying to write a procedure: when a pair starts with a, it would return b; when a pair starts with b, it would return c; and when a pair starts with c, it would return a.
(define e '((a b) (b c) (c a)))
(define (make-encoder e)
(cond ((eq? 'a (car (assq 'a e)))
(cadr (assq 'a e)))
((eq? 'b (car (assq 'b e)))
(cadr (assq 'b e)))
((eq? 'c (car (assq 'c e)))
(cadr (assq 'c e)))))
What is returned is only 'b', so I'm wondering where my brackets are wrong in cutting off the remaining code? I have played around for so long and wondering if that's my problem, or if it something else.
I don't think it's an issue of wrong parens; I can't really see a way to tweak your code to get the desired behavior. Here's how I would do it:
(define (make-encoder assoc-list)
(lambda (lst)
(define (-> elem)
(cadr (assq elem assoc-list)))
(map -> lst)))
As you can see, when you call this procedure with an association list such as e, it will return a new function that takes a list and maps -> over it, where -> looks up the element in the association list and returns result. Hence:
> ((make-encoder e) '(a b a c a b))
'(b c b a b c)
You have looking up the value of a key in a association list with (cadr (assq k a)) but what you are missing is how to apply that to every item in a list. That is where map comes in. So:
> (map (lambda (v) (cadr (assq v '((a b) (b c) (c a))))) '(a b a c a b))
'(b c b a b c)
This can be turned into a function by placing it within lambdas or a definition and replacing the values with bound names.
The program is suppose to pick out every third atom in a list.
Notice that the last atom 'p' should be picked up, but its not.
Any suggestions as to why the last atom is not being selected.
(define (every3rd lst)
(if (or (null? lst)
(null? (cdr lst)))
'()
(cons (car lst)
(every3rd (cdr(cdr(cdr lst)))))))
(every3rd '(a b c d e f g h i j k l m n o p))
Value 1: (a d g j m)
Thanks
You're missing a couple of base cases:
(define (every3rd lst)
(cond ((or (null? lst) (null? (cdr lst))) lst)
((null? (cdr (cdr lst))) (list (car lst)))
(else (cons (car lst)
(every3rd (cdr (cdr (cdr lst))))))))
See how the following cases should be handled:
(every3rd '())
=> '()
(every3rd '(a))
=> '(a)
(every3rd '(a b))
=> '(a)
(every3rd '(a b c))
=> '(a)
(every3rd '(a b c d))
=> '(a d)
(every3rd '(a b c d e f g h i j k l m n o p))
=> '(a d g j m p)
Fixing your code (covering the base cases)
It's worth noting that Scheme defines a number of c[ad]+r functions, so you can use (cdddr list) instead of (cdr (cdr (cdr list))):
(cdddr '(a b c d e f g h i))
;=> (d e f g h i)
Your code, as others have already pointed out, has the problem that it doesn't consider all of the base cases. As I see it, you have two base cases, and the second has two sub-cases:
if the list is empty, there are no elements to take at all, so you can only return the empty list.
if the list is non-empty, then there's at least one element to take, and you need to take it. However, when you recurse, there are two possibilies:
there are enough elements (three or more) and you can take the cdddr of the list; or
there are not enough elements, and the element that you took should be the last.
If you assume that <???> can somehow handle both of the subcases, then you can have this general structure:
(define (every3rd list)
(if (null? list)
'()
(cons (car list) <???>)))
Since you already know how to handle the empty list case, I think that a useful approach here is to blur the distinction between the two subcases, and simply say: "recurse on x where x is the cdddr of the list if it has one, and the empty list if it doesn't." It's easy enough to write a function maybe-cdddr that returns "the cdddr of a list if it has one, and the empty list if it doesn't":
(define (maybe-cdddr list)
(if (or (null? list)
(null? (cdr list))
(null? (cddr list)))
'()
(cdddr list)))
> (maybe-cdddr '(a b c d))
(d)
> (maybe-cdddr '(a b c))
()
> (maybe-cdddr '(a b))
()
> (maybe-cdddr '(a))
()
> (maybe-cdddr '())
()
Now you can combine these to get:
(define (every3rd list)
(if (null? list)
'()
(cons (car list) (every3rd (maybe-cdddr list)))))
> (every3rd '(a b c d e f g h i j k l m n o p))
(a d g j m)
A more modular approach
It's often easier to solve the more general problem first. In this case, that's taking each nth element from a list:
(define (take-each-nth list n)
;; Iterate down the list, accumulating elements
;; anytime that i=0. In general, each
;; step decrements i by 1, but when i=0, i
;; is reset to n-1.
(let recur ((list list) (i 0))
(cond ((null? list) '())
((zero? i) (cons (car list) (recur (cdr list) (- n 1))))
(else (recur (cdr list) (- i 1))))))
> (take-each-nth '(a b c d e f g h i j k l m n o p) 2)
(a c e g i k m o)
> (take-each-nth '(a b c d e f g h i j k l m n o p) 5)
(a f k p)
Once you've done that, it's easy to define the more particular case:
(define (every3rd list)
(take-each-nth list 3))
> (every3rd '(a b c d e f g h i j k l m n o p))
(a d g j m)
This has the advantage that you can now more easily improve the general case and maintain the same interface every3rd without having to make any changes. For instance, the implementation of take-each-nth uses some stack space in the recursive, but non-tail call in the second case. By using an accumulator, we can built the result list in reverse order, and return it when we reach the end of the list:
(define (take-each-nth list n)
;; This loop is like the one above, but uses an accumulator
;; to make all the recursive calls in tail position. When
;; i=0, a new element is added to results, and i is reset to
;; n-1. If iā 0, then i is decremented and nothing is added
;; to the results. When the list is finally empty, the
;; results are returned in reverse order.
(let recur ((list list) (i 0) (results '()))
(cond ((null? list) (reverse results))
((zero? i) (recur (cdr list) (- n 1) (cons (car list) results)))
(else (recur (cdr list) (- i 1) results)))))
It is because (null? '()) is true. you can debug what's happening with following code
(define (every3rd lst)
(if (begin
(display lst)
(newline)
(or (null? lst)
(null? (cdr lst))))
'()
(cons (car lst)
(every3rd (cdr(cdr(cdr lst)))))))
(every3rd '(a b c d e f g h i j k l m n o p))
(newline)
(display (cdr '(p)))
(newline)
(display (null? '()))
(newline)
(display (null? (cdr '(p))))
(newline)
this gives following result.
(a b c d e f g h i j k l m n o p)
(d e f g h i j k l m n o p)
(g h i j k l m n o p)
(j k l m n o p)
(m n o p)
(p)
()
#t
#t
(define rotate
(lambda (ls)
(define subrotate
(lambda (head tail res)
(if (null? tail)
res
(subrotate (append head (list (car tail)))
(cdr tail)
(cons (append tail head) res)))))
(if (null? ls)
ls
(subrotate '() ls '())))) (rotate '(a b c d e))
I want to make function that if list (a b c d e), print ((a b c d e) (b c d e a) (c d e a b) (d e a b c) (e a b c d)) but when I execute that function, it prints (e a b c d) (d e a b c) .......
I think this function will activate like
tail | head | res
'() | (a b c d e) | '()
a | (b c d e) | (b c d e a)
(a b) | (c d e) | (c d e a b)
(a b c) | (d e) | (d e a b c)
(a b c d) | (e) | (e a b c d)
(a b c d e) | () | (a b c d e)
and I expect it only print (a b c d e) but result is not. How can I modify this and why it prints every rotation?
The problem is in the way you're adding new elements to the output list. This should fix it:
(define rotate
(lambda (ls)
(define subrotate
(lambda (head tail res)
(if (null? tail)
res
(subrotate (append head (list (car tail)))
(cdr tail)
(append res (list (append tail head))))))) ; modified
(if (null? ls)
ls
(subrotate '() ls '()))))
Alternatively, you could simply reverse the output list:
(define rotate
(lambda (ls)
(define subrotate
(lambda (head tail res)
(if (null? tail)
(reverse res) ; modified
(subrotate (append head (list (car tail)))
(cdr tail)
(cons (append tail head) res)))))
(if (null? ls)
ls
(subrotate '() ls '()))))
And just for fun, here's a more compact implementation of the same algorithm, this time using a named let:
(define (rotate ls)
(let subrotate ((head '()) (tail ls) (res '()))
(if (null? tail)
(reverse res)
(subrotate (append head (list (car tail)))
(cdr tail)
(cons (append tail head) res)))))