Using Racket ISL to create a function using a foldr list abstraction - racket

How can I rewrite the total-pages function below in order to just use the foldr function rather than using foldr and map list abstractions (since using foldr and map requires going over the list twice, which is less efficient than going over the list once)?
(define (total-pages lorp)
(foldr + 0
(map num-pages lorp)))
(define (num-pages rp)
(+ 1
(-
(page-end rp)
(page-start rp))]

Before I'll show you the solution, some notes for the next time:
Add please all needed definitions and used libraries. page-end and page-start aren't defined.
Use names better than lorp and rp or explain the meaning of these names.
You have to write num-pages inside foldr function like this:
(define (total-pages lorp)
(foldr (lambda (element result)
(+ result (num-pages element)))
0
lorp))
(define (num-pages rp)
(+ 1
(-
(page-end rp)
(page-start rp))))
EDIT: Move the body of lambda into a new function:
(define (num-pages rp)
(add1
(-
(page-end rp)
(page-start rp))))
(define (add-pages element result)
(+ result (num-pages element)))
(define (total-pages lorp)
(foldr add-pages
0
lorp))

Related

using basic build-in or standard function(s) to solve problems in racket?

I'm working with lists in Racket, and I was doing a function to sum the elements of a list.
for example
(define (mysum L)
(if (empty? L) 0
(+ (first L) (mysum (rest L))))
)
then the result will be
> (mysum'(5 4))
9
>
But I would like to know what to do to multiply the numbers inside the list, rather than add them. when I put the * sign instead of + then it gives me an output of zero.
(define (myproduct L)
(if (empty? L) 0
(* (first L) (myproduct (rest L))))
)
and the result is
> (myproduct'(3 5))
0
> enter code here
I'm trying to understand how to multiply numbers in a list.
The myproduct should use 1 instead of 0 in the base case, because the identity element of multiplication is 1.
(define (myproduct L)
(if (empty? L) 1
(* (first L) (myproduct (rest L)))))
> (myproduct'(3 5))
15
A nice way to think about this is that * and + are the two operations of the field of numbers. And in any field, the two operations have identities, which are objects such that (<op> x <identity-of-op>) is x. But they have different identities. So let's define a function which tells us what the identity of the two operations is:
(define (identity-of op)
(cond
[(eqv? op +)
0]
[(eqv? op *)
1]
[else
(error "there are only two operations for the field of numbers")]))
And now we can define a general function which, given an operator, will return a function which combines a bunch of numbers using it (this function will be correct, since both * and + are associative):
(define (make-combiner op)
(define id (identity-of op))
(define (combiner numbers)
(if (null? numbers)
id
(op (first numbers) (combiner (rest numbers)))))
combiner)
And now:
(define sum-numbers (make-combiner +))
(define multiply-numbers (make-combiner *))

How to use foldr in Racket to eliminate numbers in a list that are greater than any subsequent numbers

I have to write a function in Racket using foldr that will take a list of numbers and remove list elements that are larger than any subsequent numbers.
Example: (eliminate-larger (list 1 2 3 5 4)) should produce (1 2 3 4)
I can do it without using foldr or any higher-order functions but I can't figure it out with foldr. Here's what I have:
(define (eliminate-larger lst)
(filter (lambda (z) (not(equal? z null)))
(foldr (lambda (x y)
(cons (determine-larger x (rest lst)) y)) null lst))
)
(define (determine-larger value lst)
(if (equal? (filter (lambda (x) (>= x value)) lst) lst)
value
null)
)
determine-larger will take in a value and a list and return that value if it is greater than or equal to all elements in the list. If not, it returns null. Now the eliminate-larger function is trying to go through the list and pass each value to determine-larger along with a list of every number after it. If it is a "good" value it will be returned and put in the list, if it's not a null is put in the list. Then at the end the nulls are being filtered out. My problem is getting the list of numbers that follow after the current number in the foldr function. Using "rest lst" doesn't work since it's not being done recursively like that. How do I get the rest of the numbers after x in foldr?
I really hope I'm not doing your homework for you, but here goes ...
How do I get the rest of the numbers after x in foldr?
Because you're consuming the list from the right, you can structure your accumulator such that "the rest of the numbers after x" are available as its memo argument.
(define (eliminate-larger lst)
(foldr
(lambda (member memo)
(if (andmap (lambda (n) (<= member n)) memo)
(cons member memo)
memo))
'()
lst))
(eliminate-larger (list 1 2 3 5 4)) ;; (1 2 3 4)
This is admittedly a naive solution, as you're forced to traverse the entire accumulator with each iteration, but you could easily maintain a max value, in addition to your memo, and compare against that each time through.
Following works:
(define (el lst)
(define (inner x lsti)
(if(empty? lsti) (list x)
(if(<= x (apply max lsti))
(cons x lsti)
lsti)))
(foldr inner '() lst))
(el (list 1 2 3 5 4))
Output:
'(1 2 3 4)
The cond version may be preferable:
(define (el lst)
(define (inner x lsti)
(cond
[(empty? lsti) (list x)]
[(<= x (apply max lsti)) (cons x lsti)]
[else lsti] ))
(foldr inner '() lst) )

How to use the First and Rest functions?

I am trying to use First and Rest to iterate over a list of numbers in racket but I am not sure I am using these functions correctly because the code is not working.
(define cubed
(lambda (a)
(* a a a)))
(define (all-elements-cubed a)
(cond
[(empty? a) empty]
[else
(+ 1 (all-elements-cubed (cubed (first (rest a)))))]))
(all-elements-cubed (list 1 2 3 7 5))
The first and rest procedures are the most basic building blocks for traversing a list recursively. The names are self-describing: they access the first element of a list, and the rest of the elements in a list (after the first). In your code, they should be used together with cons - the procedure for constructing lists, like this:
(define (all-elements-cubed a)
(cond
[(empty? a) empty]
[else
(cons ; we're building a new list as output, so `cons` a new element
(cubed (first a)) ; call `cubed` on the first element
(all-elements-cubed (rest a)))])) ; and proceed to the next elements
To understand why the above works remember the way we use cons for recursively building proper lists:
(cons <element> <list>)
For example:
(cons 1 (cons 2 empty))
=> '(1 2)

returning the best element from the list L according to function F?

i am trying to write a function in lisp which have 2 parameters one function F and one list L
if i place '> in place of F and list L is '(1 2 3 4 5) it will return 5 as 5 is biggest.
and if we put '< then it compares all list elements and gives the smallest one as output.
and so on.
we can even put custom written function in place of F for comparison.
i wish i could provide more sample code but i am really stuck at the start.
(DEFUN givex (F L)
(cond
(F (car L) (car (cdr L))
;after this i got stuck
)
)
another attemp to write this function
(defun best(F list)
(if (null (rest list)) (first list)
(funcall F (first List) (best (F list)))))
You are almost there, just the else clause returns the f's return value instead of the the best element:
(defun best (F list)
(let ((first (first list))
(rest (rest list)))
(if (null rest)
first
(let ((best (best f rest)))
(if (funcall F first best)
best
first)))))
Examples:
(best #'< '(1 2 3))
==> 3
(best #'> '(1 2 3))
==> 1
Note that this recursive implementation is not tail-recursive, so it is not the most efficient one. You might prefer this instead:
(defun best (f list)
(reduce (lambda (a b) (if (funcall f a b) b a)) list))
Or, better yet,
(defmacro fmax (f)
`(lambda (a b) (if (,f a b) b a)))
(reduce (fmax <) '(1 2 3))
==> 1
(reduce (fmax >) '(1 -2 3 -4) :key #'abs)
==> 1
(reduce (fmax <) '(1 -2 3 -4) :key #'abs)
==> 4

How do I find the index of an element in a list in Racket?

This is trivial implement of course, but I feel there is certainly something built in to Racket that does this. Am I correct in that intuition, and if so, what is the function?
Strangely, there isn't a built-in procedure in Racket for finding the 0-based index of an element in a list (the opposite procedure does exist, it's called list-ref). However, it's not hard to implement efficiently:
(define (index-of lst ele)
(let loop ((lst lst)
(idx 0))
(cond ((empty? lst) #f)
((equal? (first lst) ele) idx)
(else (loop (rest lst) (add1 idx))))))
But there is a similar procedure in srfi/1, it's called list-index and you can get the desired effect by passing the right parameters:
(require srfi/1)
(list-index (curry equal? 3) '(1 2 3 4 5))
=> 2
(list-index (curry equal? 6) '(1 2 3 4 5))
=> #f
UPDATE
As of Racket 6.7, index-of is now part of the standard library. Enjoy!
Here's a very simple implementation:
(define (index-of l x)
(for/or ([y l] [i (in-naturals)] #:when (equal? x y)) i))
And yes, something like this should be added to the standard library, but it's just a little tricky to do so nobody got there yet.
Note, however, that it's a feature that is very rarely useful -- since lists are usually taken as a sequence that is deconstructed using only the first/rest idiom rather than directly accessing elements. More than that, if you have a use for it and you're a newbie, then my first guess will be that you're misusing lists. Given that, the addition of such a function is likely to trip such newbies by making it more accessible. (But it will still be added, eventually.)
One can also use a built-in function 'member' which gives a sublist starting with the required item or #f if item does not exist in the list. Following compares the lengths of original list and the sublist returned by member:
(define (indexof n l)
(define sl (member n l))
(if sl
(- (length l)
(length sl))
#f))
For many situations, one may want indexes of all occurrences of item in the list. One can get a list of all indexes as follows:
(define (indexes_of1 x l)
(let loop ((l l)
(ol '())
(idx 0))
(cond
[(empty? l) (reverse ol)]
[(equal? (first l) x)
(loop (rest l)
(cons idx ol)
(add1 idx))]
[else
(loop (rest l)
ol
(add1 idx))])))
For/list can also be used for this:
(define (indexes_of2 x l)
(for/list ((i l)
(n (in-naturals))
#:when (equal? i x))
n))
Testing:
(indexes_of1 'a '(a b c a d e a f g))
(indexes_of2 'a '(a b c a d e a f g))
Output:
'(0 3 6)
'(0 3 6)