Product of squares of odd elements in list in Scheme

282 Views Asked by At

I wanted to write a code in Scheme that writes the square odd elements in list.For example (list 1 2 3 4 5) for this list it should write 225.For this purpose i write this code:

(define (square x)(* x x))

(define (product-of-square-of-odd-elements sequence)
  (cond[(odd? (car sequence)) '() (product-of-square-of-odd-elements (cdr sequence))]
       [else ((square (car sequence)) (product-of-square-of-odd-elements (cdr sequence)))]))

For run i write this (product-of-square-of-odd-elements (list 1 2 3 4 5)) and i get error like this:

car: contract violation
  expected: pair?
  given: '()

What should i do to make this code to run properly? Thank you for your answers.

3

There are 3 best solutions below

0
On

You can decompose the problem into, for example:

  1. Skip the even elements
  2. Square each element
  3. take the product of the elements

With this, an implementation is naturally expressed using simpler functions (most of which exist in Scheme) as:

(define product-of-square-of-odd-elements (l)
  (reduce * 1 (map square (skip-every-n 1 l))))

and then you implement a helper function or two, like skip-every-n.

0
On

First of all, you need to do proper formatting:

(define (square x) (* x x))

(define (product-of-square-of-odd-elements sequence)
  (cond
    [(odd? (car sequence))
     '() (product-of-square-of-odd-elements (cdr sequence))]
    [else
     ((square (car sequence)) (product-of-square-of-odd-elements (cdr sequence)))]))

Now there are multiple issues with your code:

  1. You are trying to work recursively on a sequence, but you are missing a termination case: What happens when you pass '() - the empty sequence? This is the source of your error: You cannot access the first element of an empty sequence.

  2. You need to build up your result somehow: Currently you're sending a '() into nirvana in the first branch of your cond and put a value into function call position in the second.

So let's start from scratch:

You process a sequence recursively, so you need to handle two cases:

(define (fn seq)
  (if (null? seq)
       ;; termination case
       ;; recursive case
       ))

Let's take the recursive case first: You need to compute the square and multiply it with the rest of the squares (that you'll compute next).

(* (if (odd? (car seq)
         (square (car seq))
         1)
   (fn (cdr seq)))

In the termination case you have no value to square. So you just use the unit value of multiplication: 1

This is not a good solution, as you can transform it into a tail recursive form and use higher order functions to abstract the recursion altogether. But I think that's enough for a start.

1
On

With transducers:

(define prod-square-odds
  (let ((prod-square-odds 
         ((compose (filtering odd?)
                   (mapping square)) *)))    
    (lambda (lst)
      (foldl prod-square-odds 1 lst))))


(prod-square-odds '(1 2 3 4 5))
; ==> 225

It uses reusable transducers:

(define (mapping procedure)
  (lambda (kons)
    (lambda (e acc)      
      (kons (procedure e) acc))))

(define (filtering predicate?)
  (lambda (kons)
    (lambda (e acc)
      (if (predicate? e)
          (kons e acc)
          acc))))