Question

I try to get the positive integers in Scheme but must use foldl

so... here is foldl code

foldl implementation
(define foldl
 (lambda (proc acc lst)
  (if (null? lst)
      acc
      (foldl proc
           (proc acc (car lst))
           (cdr lst)))))

then my code it should take positive integers using fold: foldl-positive-integer . I know it is wrong, I just start to learn scheme. here have to check 1) is integer? 2) is positive? 3) output should be the multiplication of all the positive e.g. input '(1 2 3 6 0 -5 "scheme") => output should be: 36

[Q1] how to implement nested-if like if(real?) if(integer?) ..... inside foldl or any other way using foldl?

(define (foldl-positive-integer)
  (foldl
    (lambda (x y) (if (real? x) (* x y) x))
    '()
    lst
))

[Q2] my code returns empty list all the time? why?

Was it helpful?

Solution

About Q1: You have to somehow skip over the elements in the list which are not positive numbers. One idea is to first filter them out, as Chris shows. An alternative would be to filter them out with foldl itself:

(define (product-of-positives lst)             ; pass input list as parameter
  (foldl (lambda (acc e)                       ; acc goes first in your foldl
           (if (and (number? e) (positive? e)) ; if it's a positive number
               (* e acc)                       ; then multiply it
               acc))                           ; otherwise keep same acc
         1                                     ; multiplicative identity
         lst))                                 ; input list

Now, for Q2: your implementation isn't right. For starters, you are not even passing a list as parameter - the list at the end is a built-in procedure, and you should not name a variable like that to avoid this kind of confusions - better use lst, for instance.

Let's say you fix that and pass along a list parameter - then you'll find out that the acc parameter isn't right, if you want to multiply a list then it must be 1, because we're building a number as the output (not a list), and it can't be 0 because it will cancel out all the values - we're multiplying them after all.

One last thing - using just real? won't work for picking the positive numbers in the list. Better stick with either of the implementations we've shown:

(product-of-positives '(1 2 3 6 0 -5 "scheme"))
=> 36

OTHER TIPS

I'm glad you included your fold since it's not consistent if the accumulator is going as the first or last argument. Now I've just loaded your code in DrRacket and renamed the variables so that I can clearly see the accumulator. The error is clear:

(define (foldl-positive-integer)
  (foldl
    (lambda (acc element) 
      (if (real? acc)      ; never real? since it's a list
          (* acc element)
          acc))
    '()                    ; acc should be the default return, perhaps 1.0?
    list))                 ; NB! using list as a variable overshadows list the procedure

A2: So for each element () is not real? so the empty list is the return for every iteration.

Now. If the result should be a real? then the initial accumulator needs to be real? as well. Perhaps 1.0. Then the tests should be done on the new element and not the accumulator which we know is real? I think a working version would be something like this:

(foldl
 (lambda (acc element) 
   (if (real? element) ; fixed from accumulator to element
       (* acc element) ; multiply if real?
       acc))           ; else just continue using the previous acc
 1.0                   ; initial accumulator
 list)

As for A1: The joining procedure can be anything using any logic. The only thing is that the previous iteration (or initial value) is the first argument and the element to process is the second. You can do this:

(define (fold-join acc e)
  (cond ((list? e) (+ acc (length e)))              ; for lists add the length
        ((and (integer? e) (negative? e) (- acc e))); negative integers, abs 
        ((integer? e) (+ acc e))                    ; positive integers
        (else acc)))                                ; ignore everything else 

(foldl fold-join 0 '((1 2 3) -5 5 2.3 9.8)) ; ==> 13
(define (product-of-positives lst)
  (foldl * 1 (filter (lambda (x)
                       (and (number? x) (positive? x)))
                     lst)))
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top