Scheme quicksort - Exception: attempt to apply non-procedure (1 2 3 4 5 7 …)

雨燕双飞 提交于 2019-12-11 08:17:44

问题


I just started learning Scheme (Petite Chez Scheme) and as a challenge to myself I'm trying to implement quicksort. However I get the following exception when I run it:

Exception: attempt to apply non-procedure (1 2 3 4 5 7 ...)

Here's my Scheme session from Emacs:

Petite Chez Scheme Version 8.4
Copyright (c) 1985-2011 Cadence Research Systems

> (define (set a i k)
    (define (reduce-list a i n)
      (if(= i n)
     a
     (reduce-list (cdr a) (+ i 1) n)))
    (if(= i 0)
       (cons k (cdr a))
       (let ((b (cons k (reduce-list a 0 (+ i 1)))))
     (let push-front ((lst b) (original-list a) (n (- i 1)))
       (if(<= n 0)
          (cons (list-ref original-list 0) lst)
          (push-front (cons (list-ref original-list n) lst) original-list (- n 1)))))))

(define (swap lst i j)
    (let ((a (list-ref lst i))
      (b (list-ref lst j)))
      (set (set lst i b) j a)))

(define (partition a i j r)
    (cond [(= j r) (cons (+ i 1) (swap a (+ i 1) j))]
      [(<= (list-ref a j) (list-ref a r)) (partition (swap a j (+ i 1)) (+ i 1) (+ j 1) r)]
      [else (partition a i (+ j 1) r)]))

(define (quicksort a p r)
    (if(< p r)
       (begin(
          (let* ((c (partition a (- p 1) p r))
            (q (car c))
            (b (quicksort (cdr c) p (- q 1))))
        (quicksort b (+ q 1) r))))
       a))

> (define lst (list 1 9 2 8 3 7 4 6 5))
> (define n (length lst))
> (trace quicksort)
(quicksort)
> (quicksort lst 0 (- n 1))
|(quicksort (1 9 2 8 3 7 4 6 5) 0 8)
| (quicksort (1 2 3 4 5 7 8 6 9) 0 3)
| |(quicksort (1 2 3 4 5 7 8 6 9) 0 2)
| | (quicksort (1 2 3 4 5 7 8 6 9) 0 1)
| | |(quicksort (1 2 3 4 5 7 8 6 9) 0 0)
| | |(1 2 3 4 5 7 8 6 9)
| | |(quicksort (1 2 3 4 5 7 8 6 9) 2 1)
| | |(1 2 3 4 5 7 8 6 9)
Exception: attempt to apply non-procedure (1 2 3 4 5 7 ...)
> 

Can anyone tell me what's going wrong? Thank you in advance


回答1:


The problem is with the

begin

in quicksort. When

(quicksort b (+ q 1) r)

eventually returns a (which is actually b in the parent quicksort), then the let* block reduces from

(define (quicksort a p r)
  (if(< p r)
     (begin(
            (let* ((c (partition a (- p 1) p r))
                   (q (car c))
                   (b (quicksort (cdr c) p (- q 1))))
              (quicksort b (+ q 1) r)))) 
     a))

to

(define (quicksort a p r)
  (if(< p r)
     (begin
        (b)) ;this is the cause of the error 
     a))

And since b is a list, trying to call it fails with an error. If you remove the begin, the let block will behave as you intend.




回答2:


In quicksort remove the (begin( and the last ) on the (quicksort b (+ q 1) r) line.

The ( after the begin, and the ) on the quicksort call line are applying the result of that second quicksort call.

This is because it is the last expression in the body of the let*, so it is the let*'s return value. The list it returns is the list that is definitely not a procedure.

Also, all lets have an implicit begin in them.

For example

(let ([a 1] [b 2] [c 3])
  (set! b 3)
  a
  b)

Would return 3 (the plain a call is a worthless and its value is ignored)

And it is equivalent to the following code:

(let ([a 1] [b 2] [c 3])
  (begin
     (set! b 3)
     a
     b))



回答3:


As others have stated the answer to your question, I'd like to clarify something missing from the other answers, that will hopefully help you and/or others with their understanding of (begin ()).

I most commonly use (begin ()) as you did in (if ()) statements because the function only has two slots after the conditional.

Thus, the (begin ()) becomes useful when intending to evaluate multiple statements for one or both sides of the conditional "split in the road", per se.

An example:

(do ([i 0 (+ i 1)]) [(< i 10)]
  (if (= (% i 2) 1)
    (printf 'odd)
    (begin
      (printf 'even)
      'even)))

Above I only use (begin ()) when I want Chez to perform two separate actions if the number i is even. When i is odd I don't need a begin statement and we can carry on.

Just a note, Chez Scheme will evaluate the contents of the begin statement in order. In The Scheme Programming Language, it says near the bottom of the page:

"The syntactic form begin [...] evaluates its subexpressions in sequence from left to right and returns the value of the last subexpression, like the body of a let or lambda expression."



来源:https://stackoverflow.com/questions/10036760/scheme-quicksort-exception-attempt-to-apply-non-procedure-1-2-3-4-5-7

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!