This is a hw assignment that requires me to write a scheme function that takes a function(with two params) and a list as parameters, then returns a list where each consecutive pair of the elements of the list is replaced by the value of the function applied to these two elements.
For example - If the list has an odd number of elements, the last element is ignored. For example, (apply-to-pairs (lambda (x y) (+ x y)) '(3 9 5 8 2 4 7)) should return (12 13 6).
so far what I have got is:
(define (fn-name fn l)
(if (null? (cdr l))null
(cons
(fn((car l)(car (cdr l)))
(fn-name fn (cdr l))))))
However, im getting this error in Racket(DrRacket):
application: not a procedure;
expected a procedure that can be applied to arguments
given: 3
arguments...:
9
... and it highlights fn((car lst)(car (cdr lst))). I'm trying to find out how to handle the function parameter. Thanks for the help!
As you already did you just apply fn like you would with any primitives like +. However you have extra parenthesis around (car lst) and (car (cdr lst)) which means you expect first element to also be a procedure you call with the second element as it's only argument and then fn only get one argument (the result of that if 3, 5 or 2 happens to be procedures) Perhaps you instead wanted (fn (car lst) (cadr lst)) (I'm using shothand for car+cdr)
Your base case should check both l and (cdr l) for null since if either one is you are fnished. (Try calling it with (fn-name + '(5))). You can use special form or to do that like (or test1 test2).
Also notice that null is not usually a bound symbol in Scheme. You either need to define it (define null '()) or use '().
EDIT ABout too many results..
Notice that when you have applied the first round withe the first two elements of the list you recurse with a new l starting at the list except the very first element.. That means you then will process 9 and 5 in the next iteration instead of 5 and 8. To fix that you need to use cddr (cdr+cdr) instead of just cdr.
Related
"Implement unique, which takes in a list s and returns a new list containing the same elements as s with duplicates removed."
scm> (unique '(1 2 1 3 2 3 1))
(1 2 3)
scm> (unique '(a b c a a b b c))
(a b c)
What I've tried so far is:
(define (unique s)
(cond
((null? s) nil)
(else (cons (car s)(filter ?)
This question required to use the built-in filter function. The general format of filter function is (filter predicate lst), and I was stuck on the predicate part. I am thinking it should be a lambda function. Also, what should I do to solve this question recursively?
(filter predicate list) returns a new list obtained by eliminating all the elements of the list that does not satisfy the predicate. So if you get the first element of the list, to eliminate its duplicates, if they exists, you could simply eliminate from the rest of the list all the elements equal to it, something like:
(filter
(lambda (x) (not (eqv? x (first lst)))) ; what to maintain: all the elements different from (first lst)
(rest lst)) ; the list from which to eleminate it
for instance:
(filter (lambda (x) (not (eqv? x 1))) '(2 1 3 2 1 4))
produces (2 3 2 1 4), eliminating all the occurrences of 1.
Then if you cons the first element with the list resulting from the filter, you are sure that there is only a “copy” of that element in the resulting list.
The last step needed to write your function is to repeat recursively this process. In general, when you have to apply a recursive process, you have to find a terminal case, in which the result of the function can be immediately given (as the empty list for lists), and the general case, in which you express the solution assuming that you have already available the function for a “smaller” input (for instance a list with a lesser number of elements).
Consider this definition:
define (unique s)
(if (null? s)
'()
(cons (first s)
(filter
(lambda (x) (not (eq? x (first s))))
(unique (rest s))))))
(rest s) is a list which has shorter than s. So you can apply unique to it and find a list without duplicates. If, from this list, you remove the duplicates of the first element with filter, and then cons this element at the beginning of the result, you have a list without any duplicate.
And this is a possibile solution to your problem.
New to scheme but trying to learn the basics.
Let's say I passed a list in as a parameter and I wanted to multiply each element by -1. Right now I have this:
(define (negative b)
(* (car b) -1 )))
Which returns the first element as -1 * that element
So in this case giving it (negative '(5 1 2 3)) returns -5.
But lets say I want it to return
-5 -1 -2 -3
How would I go about making the rest of the list negative? Using cdr recursively?
Do it recursively.
(define (negative l)
(if (null? l)
'()
(cons (* (car l) -1)
(negative (cdr l)))))
If the list is empty, this just returns an empty list, as the base case.
Otherwise, it calculates -1 * the first element, the negative of the rest of the list, and combines them to produce the result.
The purpose of your exercise may be for you to code up your own map procedure, in which case that's fine. But if not, use scheme's built in 'map' procedure which is intended for just this kind of purpose.
'map' has been available at least since R4RS (that is, a long time ago) and possibly earlier.
by using map. If you want it returned as list.
It would be like this
(define negative
(lambda (b)
(map - b)))
Map is going through list b, and apply procedure "-" to each number in list
If you want to return as single numbers not in list you apply values on the list.
(define negative1
(lambda (b)
(apply values (map - b))))
Edit: I saw that you are asking for recursive solution, which would go like this
(define negative1
(lambda (b)
(if (null? b)
'()
(cons (- (car b)) (negative1 (cdr b))))))
This must be very easy to accomplish but I am new to racket and dont know how:
I have a list (1 2 3 4) and would like to convert it into (1)(2)(3)(4)
Or is there a way to build it as (1)(2)(3)(4). I am using
cons '(element) call-function
to build it inside a function (recursively)
Try this:
(map list '(1 2 3 4))
From your text, I see that you do '(element). Problem with that is that everything which is quoted is never anything but what you see. Thus if element happens to be a variable it won't be expanded because of the quote.
The right way to get a list with one element would be to use list. eg. (list element) to get whatever the variable element to be the one element in your list. However, you won't need this in a roll-your-own recursive procedure:
(define (listify lst)
(if (null? lst) ; if lst is null we are done
'() ; evaluate to the empty list
(cons (list (car lst)) ; else we make a list with the first element
(listify (cdr lst))))) ; and listify the rest of the list too
Most of the procedure now is facilitating going through the argument, but since it's a common thing to do we can use higher order procedures with foldr so that you only concentrating on what is going to happen with the element in this chain in correspondence with the rest of the process:
(define (listify lst)
(foldr (lambda (e acc)
(cons (list e) ; chain this element wrapped in a list
acc)) ; with the result from the rest of the list
'() ; initiate with an empty list
lst)) ; go through lst
Of course, since we do something with each element in a list and nothing fancy by using map we only need to supply what to do with each element rather telling how to join the chains in the list together as well.
(define (listify lst)
(map list lst)) ; make a new list by applying a list of each element
It's actually a single argument version of zip:
(require srfi/1)
(zip '(1 2 3 4)) ; ==> ((1) (2) (3) (4))
(zip '(1 2 3) '(a b c)) ; ==> ((1 a) (2 b) (3 c))
There you go. As simple as it can get.
I am a newbie in scheme and I am trying to write a procedure which always finds a list's tail's first element. This is important in recursive calls.
Here is my procedure :
(define second (lambda (x) (car(cdr(x))))
and this is how i try to check it whether it runs correctly or not:
>(define x (list 1 2 3 4))
>(second x)
and this is the error :
procedure application: expected procedure, given: (1 2 3 4) (no arguments)
=== context ===
stdin::184: second
/usr/share/racket/collects/racket/private/misc.rkt:85:7
What might be the problem? Can you give me an inspiration? Is my definition of "second" wrong or what?
Thanks in advance.
There's an extra, unnecessary pair of parenthesis in your code. This fixes it:
(define second (lambda (x) (car (cdr x))))
To be clear, this was wrong: (cdr(x)). The correct form is: (cdr x). Remember, whenever you need to apply a function f to an argument x the correct way is: (f x).
Scheme uses S-expressions, so instead of car(x), you should use (car x). In your case, that means (car (cdr x)), not car(cdr(x)).
How do we verify in scheme with the do cicle, if an element of the first list is in the second?
The do loop in racket has an interesting structure:
(do ([id init-expr step-expr-maybe] ...)
(stop?-expr finish-expr ...)
expr ...)
The documentation for r5rs provides an example:
(let ((x '(1 3 5 7 9)))
(do ((x x (cdr x))
(sum 0 (+ sum (car x))))
((null? x) sum)))
That statement returns 25, the sum of the elements of the loop. The x in the do loop is initialized to the x in the let, and then iteratively set to the cdr of itself each time through the loop. sum is initialized to 0, and accumulates the value of the car of x each time through. The stopping condition is when the iteration variable is empty, and the return value is the sum.
Ok, aside from the racket preference of square brackets, this looks good. There's a do loop and a list. The loop does something over that list. We can use that to write a function that finds a specific atom in a list (using the racket brackets):
(define (find5 lst)
(do ([x lst (rest x)]
[found #f (or found (eq? 5 (first x)))])
((null? x) found)))
Instead of initializing and adding the value sum, I or into found. Also, I prefer first and rest over car and cdr and define them myself when they don't exist. The way this function works should follow from the explanation of the example.
(find5 '(1 2 3 4 6))
Gives #f, as expected. Similarly:
(find5 '(1 2 3 4 5 6))
Gives #t.
Are you able to generalize finding a specific element in a list with a do loop into your specific question?