0

This program takes a list where elements are repeated, e.g L = (a a a b b b c c c d), and output a list of items and number of repetition e.g ((a 3)(b 3)(c 3) d)

(define counter 0)
(define (compress liste)
(if (or (null? liste) (null? (cdr liste)))
   liste
(let ((compressed-cdr (compress (cdr liste)))) 
   (if (equal? (car liste) (car compressed-cdr))
   ((+ counter 1) compressed-cdr)
  ((cons (car liste) counter) (= counter 0) (compressed-cdr))))
                       ))

However, I get this error:

Error: application: not a procedure; expected a procedure that can be applied to arguments
given: 1 arguments ...

The error is at the true predicate of the second if condition.

Will Ness
  • 70,110
  • 9
  • 98
  • 181
user3241846
  • 643
  • 3
  • 9
  • 26

3 Answers3

1

It was hard for me to figure out where the problem is in your code. I tried the following that seems to work.

(define (compress liste)

  (define (helper in prev out)
     (if (null? in)
        (list (list (car out) (length out)))
        (if (equal? prev (car in))
          (helper (cdr in) prev (append out (list (car in))))
          (cons (list (car out) (length out)) (compress in)))))


    (if (null? liste)
      '()
      (helper (cdr liste) (car liste) (list (car liste))))
      )

It uses helper to gather the output for matching items. When it finds a mismatch, it calls the main function to process the rest of the list. helper simply prepends its results to the results obtained from the main function.

A slightly improved version:

(define (compress liste)

  (define (helper in prev out)
     (if (null? in)
        (list (list prev out))
        (if (equal? prev (car in))
          (helper (cdr in) prev (+ 1 out))
          (cons (list prev out) (compress in)))))

    (if (null? liste)
      '()
      (helper (cdr liste) (car liste) 1))
      )

Here's tail-recursive version:

(define (compress liste)

  (define (helper-1 in out)
    (if (null? in)
      '()
      (helper-2 (cdr in) (car in) 1 out)))

  (define (helper-2 in prev count out)
    (if (null? in)
      (append out (list (list prev count)))
      (if (equal? prev (car in))
        (helper-2 (cdr in) prev (+ 1 count) out)
        (helper-1 in (append out (list (list prev count)))))))

  (helper-1 liste '()))
R Sahu
  • 204,454
  • 14
  • 159
  • 270
1

As the error message says, the problem is located "at the true predicate of the second if condition":

((+ counter 1) compressed-cdr)

In this case, (+ counter 1) should evaluate to a procedure but it evaluates to a number. I think the problem is that you don't know how to increment the counter.

Your false predicate has the same problem:

((cons (car liste) counter) (= counter 0) (compressed-cdr))))))

where (cons (car liste) counter) yields a list and not a procedure.

I don't think we could really work with this code. I suggest looking at R Sahu's answer, which is close. Alternatively, I can show you a tail-recursive version which you could also have a look at. BTW, this is called run-length encoding, hence I've called my procedure rle:

(define (rle lst)

  (define (newres prv cnt res)
    (case cnt
      ((0)  res) 
      ((1)  (cons prv res)) 
      (else (cons (list prv cnt) res))))

  (let loop ((lst lst) (prv null) (cnt 0) (res null))
    (if (null? lst)
        (if (zero? cnt)
            (reverse res)
            (loop null null 0 (newres prv cnt res)))
        (let ((c (car lst)))
          (if (eq? c prv)
              (loop (cdr lst) prv (add1 cnt) res)
              (loop (cdr lst) c 1 (newres prv cnt res)))))))
Community
  • 1
  • 1
uselpa
  • 18,732
  • 2
  • 34
  • 52
1

Building the result list in a top-down manner, with the "head-sentinel trick", for simplicity:

(define (rle lst)
  (if (null? lst) 
   '()
   (let ((res (list 1)))        ; head sentinel
      (let loop ((p   res)      ; result's last cons cell  
                 (elt (car lst))
                 (cnt 1) 
                 (lst (cdr lst)))
         (if (and (not (null? lst))
                  (equal? elt (car lst)))
            (loop p elt (+ cnt 1) (cdr lst))
            (begin
               (set-cdr! p (list (if (= 1 cnt) elt (list elt cnt))))
               (if (null? lst)
                  (cdr res)     ; skip the head in result, on return
                  (loop (cdr p) (car lst) 1 (cdr lst)))))))))

As @uselpa explained, this is called run-length encoding; for the uniformity of the result I'd suggest using (x 1) representation for non-repeating elements.

And the error "Error: application: not a procedure; expected a procedure", as others have said, means that the system expected to find a procedure but found something else, so can't apply it. Scheme expects to find a procedure as the first form in a list: (proc args ...), and tries to apply it to the arguments. But in your code it is not a procedure, but some other type of data.


If your Scheme has left fold, or reduce, you can run through it twice - first collecting the uniform results, and then applying your special format while reversing (left fold's results are usually built in reversed order):

(define (fold f init lst)            ; if fold is not defined,
   (reduce f init (cons init lst)))  ;   define it in terms of reduce

(define (rle lst)
   (fold (lambda (x acc)             ; NB! MIT-Scheme: (acc x)
             (if (= 1 (cadr x))  (cons (car x) acc)  (cons x acc)))
         '()
      (fold (lambda (x acc)          ; NB! MIT-Scheme: (acc x)
                (if (or (null? acc) (not (equal? (caar acc) x)))
                   (cons (list x 1) acc)
                   (cons (list x (+ (cadar acc) 1)) (cdr acc))))
            '() 
            lst)))
Will Ness
  • 70,110
  • 9
  • 98
  • 181