I already have the code to reverse a list:
(define (myreverse lst)
(if (null? lst)
lst
(append (reverse (cdr lst))
(list (car lst)))))
But I want to do this using only lectrec, cons, car and cdr. How can I do that?
The standard way to reverse a list without append is to use the helper function REVAPPEND, like this:
(define (reverse x) (revappend x '()))
(define (revappend x y)
(if (null? x)
y
(revappend (cdr x) (cons (car x) y))))
Now if you want to implement reverse as a single function you can use LETREC to locally define the REVAPPEND helper, like this
(define (reverse x)
(let revappend ((x x) (y '()))
...))
This is just a template to get you started, feel free to ask if you need more help.
Related
I have this code:
(define remove
(λ (x y)
(cond
((null? y) '())
((eq? x (car y)) (delete x (cdr y)))
(else (cons (car y) (delete x (cdr y))))
)))
Input: (remove 'c '(w((x)(c q)(((o))))w))
This will not go inside the inner parenthesis. If I try to remove 'w', it will remove all occurrences of it because they are outside of the parenthesis. So, I can't take out anything from the inside.
The solution is a bit more elaborate, you'll have to use the template for traversing a list of lists. Also, is better to use equal? instead of eq?, consult the documentation to understand the differences. A possible implementation follows, I took the liberty of renaming the parameters to something more meaningful:
(define remove
(λ (ele lst)
(cond
((null? lst) '()) ; if the list is empty then we're done
((not (pair? (car lst))) ; if the first element is an atom
(if (equal? (car lst) ele) ; check if it's the one we're looking for
(remove ele (cdr lst)) ; if so we skip over it, eliminating it
(cons (car lst) (remove ele (cdr lst))))) ; otherwise we add it
(else (cons (remove ele (car lst)) ; else advance recursion
(remove ele (cdr lst))))))) ; over both `car` and `cdr`
Now it works as expected:
(remove 'c '(w ((x) (c q) (((o)))) w))
=> '(w ((x) (q) (((o)))) w)
So, from the SICP we know that the cons car and cdr can be defined as a procedure:
(define (cons x y)
(lambda (m) (m x y)))
(define (car z)
(z (lambda (p q) p)))
(define (cdr z)
(z (lambda (p q) q)))
But the pre-defined procedure list, which takes the arguments to build a list, uses the original cons. That means, a list that list built, isn't a procedure as I want.
(car (list 1 2 3))
;The Object (1 2 3) is not applicable
So i write this:
(define (list . l)
(if (null? l)
'()
(cons (original-car l)
(list (original-cdr l)))))
I just wondering how to define the original-car and original-cdr. Are there some way to make a copy of a procedure in Scheme? Or there's some alternate way to solve this problem. thx
If you need to save a reference to the "original" procedures before redefining them, simply create an alias before defining the "new" procedures (I guess that's what you mean by "copying" them). Like this:
(define original-cons cons)
(define original-car car)
(define original-cdr cdr)
(define original-list list)
In this way, the old procedures can still be used, as long as we refer to them by their new names. In other words, the implementation of cons, car, cdr and list as procedures will look like this:
(define (my-cons x y)
(lambda (m) (m x y)))
(define (my-car z)
(z (lambda (p q) p)))
(define (my-cdr z)
(z (lambda (p q) q)))
(define (my-list . els)
(if (null? els)
'()
(my-cons
(original-car els)
(apply my-list (original-cdr els)))))
And sure enough, it works:
(define lst (my-list 1 2 3 4))
lst
=> #<procedure>
(my-car lst)
=> 1
(my-car (my-cdr lst))
=> 2
List in an implementation is defined as
(define (list . l) l)
However, this is using a lot of the underlying implementation. E.g. to work it uses the native cons. cons as defined in SICP is a thought experiment so you're implementation needs a little correction:
(define (my-cons x y)
(lambda (m) (m x y)))
(define (my-car z)
(z (lambda (p q) p)))
(define (my-cdr z)
(z (lambda (p q) q)))
(define (my-list . l)
(define (my-list-aux l)
(if (null? l)
'()
(my-cons (car l)
(my-list-aux (cdr l)))))
(my-list-aux l))
;; optional, update binding
(define car my-car)
(define cdr my-cdr)
(define list my-list)
my-cons my-car, my-cdr and my-list are as defined in your question. Only change is reference to correct procedure (with name not conflicting with Scheme)
I have been working on a call to accumulate which goes as follows:
(define (accumulate op initial sequence)
(if (null? sequence)
initial
(op (car sequence)
(accumulate op initial (cdr sequence)))))
However when I try to square something by slecting it through filter the answer doesn't work. What I have so far is this:
(define (f2b items)
(accumulate (lambda (x y)
(cons (append
(map square (filter negative? (filter number? x))) x) y)) () items)
)
The Input I give is:
(f2a '(("sdas" 89) (-53 "sad")))
The output I get is:
((sdas 89) (2809 -53 sad))
I can't seem to get the negative number to go away.
It would be much easier to use filter and map. Filter is predefined but it looks like this.
(define (filter1 predicate sequence)
(cond
((null? sequence) null)
((predicate (car sequence))
(cons (car sequence)
(filter predicate (cdr sequence))))
(else (filter predicate (cdr sequence)))))
map is also predefined, it just runs a function over a list.
This should be pretty simple to write, but incase you need help you should just write a lamdba for the predicate in filter.
Actually, the functionality you describe is not usually the job of an accumulator. Instead, squaring negative numbers in a list seems like the perfect job for something like a map.
First, let's do:
(define (make-positive x)
(if (and (number? x) (negative? x))
(square x)
x))
Now suppose we want to operate on a list called lst. If it was just a flat list, like '(1 "2" -5 -4 6), then we could just
(map make-positive lst)
Since we need to operate on lists which are nested two levels deep, we could do:
(map (lambda (x)
(map make-positive x))
lst)
If we wanted to operate on lists which are nested arbitrarily deep, we could do:
(define (nested-map fn elm)
(if (list? elm)
(map (lambda (x) (nested-map fn x)) elm)
(fn elm)))
(nested-map make-positive lst)
PS - we can define map like this:
(define (map fn lst)
(if (empty? lst)
'()
(cons (fn (car lst))
(map fn (cdr lst)))))
I wrote this code to create a list from en number of arguments given
(define (create-list . e)
e)
But I need it to remove any duplicated numbers from the list within this block itself.
I have tried and searched for hours and can't find a solution without placing dozens of lines of code on other blocks.
For example let's say my input is
(create-list . 2 2 3 5 5 )
I need the list created to be '(2 3 5) and not '(2 2 3 5 5 )...
The order of the numbers doesn't matter.
Basically, you need to do something like:
(define (create-list . e) (dedupe e))
I can think of a really simple but probably inefficient way to do this:
(define (dedupe e)
(if (null? e) '()
(cons (car e) (dedupe (filter (lambda (x) (not (equal? x (car e))))
(cdr e))))))
If you can't use existing functions like filter, you can make one yourself:
(define (my-filter pred ls)
(cond ((null? ls) '())
((pred (car ls)) (cons (car ls) (my-filter pred (cdr ls))))
(else (my-filter pred (cdr ls)))))
This one is faster:
(define (remove-duplicates l)
(cond ((null? l)
'())
((member (car l) (cdr l))
(remove-duplicates (cdr l)))
(else
(cons (car l) (remove-duplicates (cdr l))))))
But even better,
mit-scheme provides delete-duplicates, which does exactly what you want.
The most efficient (traversing the list once) way to do this is to define a function which goes through the list element-by-element. The function stores a list of which elements are already in the de-duped list.
An advantage of this solution over #Tikhon Jelvis's, is that the list elements don't need to be in order, to be deduplicated.
Given a function elem, which says if a is an element of l:
(define (elem? a l)
(cond ((null? l) #f)
((equal? a (car l)) #t)
(else (elem? a (cdr l)))))
We can traverse the list, storing each element we haven't seen before:
(define (de_dupe l_remaining already_contains)
(cond ((null? l_remaining) already_contains)
((elem? (car l_remaining) already_contains) (de_dupe (cdr l_remaining) already_contains))
(else (de_dupe (cdr l_remaining) (cons (car l_remaining) already_contains)))))
Note: for efficiency, this returns the elements in reverse order
(define (delete x)
(cond
((null? x) x)
((= (length x) 1) x) | ((null? (cdr x)) x)
((= (car x) (cadr x)) (delete (cdr x)))
(#t (cons (car x) (delete (cdr x))))
)
)
im trying to write a function in Scheme where i accept a list and return all the different derangements (look below for definition) as a list of lists
derangement: A list where no item is in the same place as the original list
ex: '(a b c) -> '(cab)
any help is appreciated!
Compute all of the permutations of the input list and then filter out the ones that have an element in the same position as the input list. If you need more detail, leave a comment.
Edit 1:
Define (or maybe it's defined already? Good exercise, anyway) a procedure called filter that takes as its first argument a procedure p and a list l as its second argument. Return a list containing only the values for which (p l) returns a truthy value.
Define a procedure derangement? that tests if a list l1 is a derangement of l2. This will be handy when paired with filter.
The most obvious solution would be something like this:
(define filtered-permutations
(lambda (lst)
(filter
(lambda (permuted-list)
(deranged? permuted-list lst))
(permute lst))))
Since the number of derangements is considerably lower than then number of permutations, however, this is not very efficient. Here is a solution that mostly avoids generating permutations that are not derangements, but does use filter once, for the sake of simplicity:
(define deranged?
(lambda (lst1 lst2)
(if (null? lst1)
#t
(if (eq? (car lst1) (car lst2))
#f
(deranged? (cdr lst1) (cdr lst2))))))
(define derange
(lambda (lst)
(if (< (length lst) 2)
;; a list of zero or one elements can not be deranged
'()
(permute-helper lst lst))))
(define derange-helper
(lambda (lst template)
(if (= 2 (length lst))
(let ((one (car lst))
(two (cadr lst)))
(filter
(lambda (x)
(deranged? x template))
(list (list one two) (list two one))))
(let ((anchor (car template)))
(let loop ((todo lst)
(done '())
(result '()))
(if (null? todo)
result
(let ((item (car todo)))
(if (eq? item anchor)
;; this permutation would not be a derangement
(loop (cdr todo)
(cons item done)
result)
(let ((permutations
(map
(lambda (x)
(cons item x))
(derange-helper (append (cdr todo) done)
(cdr template)))))
(loop (cdr todo)
(cons item done)
(append result permutations)))))))))))