Sort function with customizable comparision function - sorting

After writing:
(define (sort-asc l)
(cond ((eq? l '()) '())
((eq? (cdr l) '()) (list (car l)))
((< (car l) (cadr l)) (cons (car l) (sort-asc (cdr l)) ))
(else (cons (cadr l) (sort-asc (cons (car l) (cddr l)) )))))
How do you write a function that can additionally take a comparison function as a parameter?
Tried:
(define (sort-f l f)
(cond ((eq? l '()) '())
((eq? (cdr l) '()) (list (car l)))
((lambda ()(f (car l) (cadr l))) (cons (car l) (sort-f (cdr l) f)))
(else (cons (cadr l) (sort-f (cons (car l) (cddr l)) f)))))
But (sort-f '(4 3 8 2 5) <) returns the same list.
p.s. Is there any way to make this code look more elegant by somehow rewriting of all the car's, cadr's and cdr's?

Your third cond branch condition should be (f (car l) (cadr l)), not (lambda () ...). The lambda expression returns a procedure (which is not invoked), and since all procedures are truthy, the fourth (else) branch is never reached.
That is,
((lambda ()(f (car l) (cadr l))) (cons (car l) (sort-f (cdr l) f)))
should be
((f (car l) (cadr l)) (cons (car l) (sort-f (cdr l) f)))

Related

Create palindrom function without append function in output in scheme

i am trying to create palyndrom function which is doing palyndrom from input string. Something like this: (palindrome '(1 2 3 4)) ==> (1 2 3 4 3 2 1).
I have created this code below but it is returning me (palindrome '(1 2 3 4)) ==> (1 (2 (3 (4) 3) 2) 1)
My code is below. Task is to NOT use append or reverse.
(define (palindrome l)
(cond
((null? (cdr l)) (list (car l)))
((list (car l) (palindrome (cdr l)) (car l)))))
Thanks for help.
As in the comment of Sylwester, you can do your own version of append or reverse. Here is an example in which only the append function (called concatenate) is defined.
(define (palindrome l)
(define (concatenate l1 l2)
(if (null? l1)
l2
(cons (car l1) (concatenate (cdr l1) l2))))
(define (p l)
(cond ((null? l) '())
((null? (cdr l)) l)
(else (cons (car l) (concatenate (p (cdr l)) (list (car l)))))))
(p l))
(palindrome '(1 2 3 4))
'(1 2 3 4 3 2 1)
Here instead is a tail recursive version:
(define (palindrome l)
(define (concatenate l1 l2)
(if (null? l1)
l2
(cons (car l1) (concatenate (cdr l1) l2))))
(define (p l prefix suffix)
(cond ((null? l) (concatenate prefix suffix))
((null? (cdr l)) (concatenate prefix (cons (car l) suffix)))
(else (p (cdr l) (concatenate prefix (list (car l))) (cons (car l) suffix)))))
(p l '() '()))

Returning two parts of a list as a pair

In my program, I am supposed to write a function where it splits a list into even and odd. The problem is that the output/syntax is incorrect. I am getting ((1 3) (2 4)) when testing out the example (split '(1 2 3 4)). The output needs to look like ((1 3) 2 4)
Here is my code:
(define (split l)
(define (odd l)
(if (null? l) '()
(if (null? (cdr l)) (list (car l))
(cons (car l) (odd (cddr l))))))
(define (even l)
(if (null? l) '()
(if (null? (cdr l)) '()
(cons (cadr l) (even (cddr l))))))
(cons (odd l) (cons (even l) '())))
(even l) is already a list. You don't need to wrap it in an extra cons.
The code below should work.
(define (split l)
(define (odd l)
(if (null? l) '()
(if (null? (cdr l)) (list (car l))
(cons (car l) (odd (cddr l))))))
(define (even l)
(if (null? l) '()
(if (null? (cdr l)) '()
(cons (cadr l) (even (cddr l))))))
(cons (odd l) (even l)))

Rotating a list to the right in scheme

if this is rotating a list to the left:
(define (rotate-left l)
(if (null? l)
'()
(append (cdr l) (cons(car l) '()))))
How would I rotate a list to the right?
If you're ok with writing a helper function to find the last element, it's pretty easy to do a recursive implementation:
(define rotate-right
(lambda (lis full)
(if (null? (cdr lis))
(cons (car lis) (get-all-but-last full))
(rotate-right (cdr lis) full))))
(define get-all-but-last
(lambda (lis)
(if (null? (cdr lis))
'()
(cons (car lis) (get-all-but-last (cdr lis))))))
Here is a short non-recursive solution:
(define (rotate-right l)
(let ((rev (reverse l)))
(cons (car rev) (reverse (cdr rev)))))
And here is a iterative solution:
(define (rotate-right l)
(let iter ((remain l)
(output '()))
(if (null? (cdr remain))
(cons (car remain) (reverse output))
(iter (cdr remain) (cons (car remain) output)))))
(rotate-right '(1 2 3 4 5)) ;==> (5 1 2 3 4)

The Liitle Schemer 4th page81 rember* function

I'm studying The Liitle Schemer 4th.
Sometimes I have a different solution. It confuses me and I can't easily understand the standard answer of the book.
For example, with rember*:
My solution is :
(define rember*
(lambda (a l)
(cond
((null? l) '())
((atom? l) l)
((eq? a (car l)) (rember* a (cdr l)))
(else (cons (rember* a (car l)) (rember* a (cdr l)))))))
The book's solution:
(define rember*
(lambda (a l)
(cond
((null? l) '())
((atom? (car l))
(cond
((eq? (car l) a)
(rember* a (cdr l)))
(else (cons (car l)
(rember* a (car l))))))
(else (cons (rember* a (car l))
(rember* a (cdr l)))))))
Which is better?
One more question.
Original structure:
(define rember*
(lambda (a l)
(cond
((null? l) '())
((atom? (car l))
(cond
((eq? (car l) a)
(rember* a (cdr l)))
(else (cons (car l)
(rember* a (car l))))))
(else (cons (rember* a (car l))
(rember* a (cdr l)))))))
New structrue:
(define rember*
(lambda (a l)
(cond
((null? l) '())
((atom? (car l)) (cond
((eq? (car l) a) (rember* a (cdr l)))
(else (cons (car l) (rember* a (cdr l))))))
(else (cons (rember* a (car l)) (rember* a (cdr l)))))))
Which is better for everyone?
In general, is not unusual that the same function is implemented by different programs. In your example, however, the two programs implement different functions, so that I think is not immediate to say “which is the best”.
The second program (that of the book), implements a function defined over the domain of the lists, and only that domain. So, you cannot give to it an atom, for instance, since it would produce an error.
The first one (your version), on the other hand, can be applied to lists (and in this case has the same behaviour of the second one), but can be applied also to atoms, so that you can do, for instance:
(rember* 'a 'a) ; returns a
(rember* 'a 'b) ; returns b
So, one should look at the specification of the function, and see if a program implements in a consistent way this specification. I would say that the first program in not entirely consistent with the specification of the function (remove an element from the second argument), but this is just an opinion, since the function is well defined only over the domain of the lists.

How to use self-compose with sort-step to sort

(define (compose f1 f2)
(lambda (p2) (f1 (f2 p2))))
(define (self-compose f n)
(if (= n 1) (compose f f)
(compose f (self-compose f (- n 1)))))
(define (sort-step l f)
(cond ((eq? l '()) '())
((eq? (cdr l) '()) (list (car l)))
((f (car l) (cadr l)) (cons (car l) (sort-step (cdr l) f)))
(else (cons (cadr l) (sort-step (cons (car l) (cddr l)) f)))))
How to use self-compose with sort-step to sort?
Tried:
(define (sort-f l f)
(self-compose (sort-step l f) (length l)))
test:
(sort-f '(8 4 6 5 3) >) ===> arity mismatch;
the expected number of arguments does not match the given number
expected: 1
given: 0
(sort-step l f) is not a function of one argument as compose expects, it's a list.
Since you probably want to "thread" the list through the composition, you need to compose a function that takes a list and returns a list.
You can get one by rearranging sort-step slightly into a curried function:
(define (sort-step f)
(lambda (l)
(cond ((null? l) '())
((null? (cdr l)) l)
((f (car l) (cadr l)) (cons (car l) ((sort-step f) (cdr l))))
(else (cons (cadr l) ((sort-step f) (cons (car l) (cddr l))))))))
Now (sort-step f) is a function from list to list and you can say
(define (sort-f l f)
((self-compose (sort-step f) (length l)) l))
The l param can also be thread by a lambda in the self-compose without rewriting sort-step:
(define (sort-f l f)
((self-compose (lambda (l) (sort-step l f)) (length l)) l))

Resources