Question

(define lista (list 1/2 2/3 3/4 4/5 5/6))
(define l (length lista))

(define suma (
lambda() (
    (let s((i 0))
        (if (= l 1)
            (list-ref lista i)
            (   (if(< i (- l 2))
                    (+ (list-ref lista i) (s (+ i 1)))      
                )
            )
        )
    )
)   
)
)

I get the following error when I run (suma):

attempt to apply non-procedure #<void>.

I am new at this so please help. Thank you!

Was it helpful?

Solution

The simplest way to add all the elements in a list would be to use apply:

(apply + lista)
=> 3 11/20

But I guess you want to implement this from scratch. Your procedure has lots of parentheses errors, and the way you're iterating over the list (using list-ref) is not idiomatic - in Scheme we use recursion to traverse lists, not indexes. Fixing it requires quite a bit of work:

(define suma
  (lambda ()
    (let s ((i 0))
      (if (= i (- l 1))
          (list-ref lista i)
          (+ (list-ref lista i)
             (s (+ i 1)))))))

But still, even if we were to solve this problem using explicit recursion, the above is not idiomatic. A solution more in the spirit of Scheme would look as follows, and notice the template for traversing a list:

(define (suma lst)           ; pass the list as a parameter
  (if (null? lst)            ; is the list empty? then
      0                      ; we've reached the base case, return 0
      (+ (car lst)           ; otherwise add the current element
         (suma (cdr lst))))) ; and advance the recursion

Alternatively, we could use tail recursion to write a more efficient solution:

(define (suma lst)
  (let s ((lst lst)              ; list to traverse
          (acc 0))               ; accumulated result
    (if (null? lst)              ; if the list is empty
        acc                      ; return the accumulator
        (s (cdr lst)             ; otherwise advance recursion
           (+ (car lst) acc))))) ; and update accumulator

Either way, we pass the input list as parameter and it works as expected:

(suma lista)
=> 3 11/20

OTHER TIPS

The simplest answer, and the one that experienced Scheme programmers would doubtless use, is this:

(define (sum xs) (apply + xs))

If you want a recursive solution, you can use this:

(define (sum xs) (if (null? xs) 0 (+ (car xs) (sum (cdr xs)))))

For an iterative, tail-recursive solution you can use named let:

(define (sum xs)
  (let loop ((xs xs) (sum 0))
    (if (null? xs) sum
      (loop (cdr xs) (+ sum (car xs))))))

Here is another iterative solution, using do:

(define (sum xs)
  (do ((xs xs (cdr xs)) (sum 0 (+ sum (car xs))))
      ((null? xs) sum)))

If you insist on using list-ref, here is a solution; it will be the least efficient of those shown here, because list-ref repeatedly traverses the list:

(define (sum xs)
  (let ((len (length xs)))
    (let loop ((i 0) (sum 0))
      (if (= i len) sum
        (loop (+ i 1) (+ sum (list-ref xs i)))))))

You should make sure you understand all these solutions, because they express a variety of Scheme idioms that you will find useful in your future programming.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top