1

我刚开始学习 Scheme(Petite Chez Scheme),作为对自己的挑战,我正在尝试实施快速排序。但是,当我运行它时出现以下异常:

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

这是我在 Emacs 中的 Scheme 会话:

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 ...)
> 

谁能告诉我出了什么问题?先感谢您

4

3 回答 3

1

问题在于

begin

在快速排序中。什么时候

(quicksort b (+ q 1) r)

最终返回 a (实际上是父快速排序中的 b ),然后 let* 块从

(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 (quicksort a p r)
  (if(< p r)
     (begin
        (b)) ;this is the cause of the error 
     a))

由于 b 是一个列表,因此尝试调用它会失败并出现错误。如果您删除 begin,let 块将按照您的意图运行。

于 2012-04-06T00:38:10.253 回答
0

在快速排序中删除(begin(最后)一行(quicksort b (+ q 1) r)

快速排序调用行上的和(之后的是应用第二次快速排序调用的结果。begin)

这是因为它是函数体中的最后一个表达式let*,所以它是 let* 的返回值。它返回的列表是绝对不是过程的列表。

此外,所有让它们都有一个隐含的开始。

例如

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

将返回 3(简单的调用是毫无价值的,它的值被忽略)

它等价于以下代码:

(let ([a 1] [b 2] [c 3])
  (begin
     (set! b 3)
     a
     b))
于 2012-04-06T00:41:36.943 回答
0

正如其他人已经说明了您的问题的答案,我想澄清其他答案中缺少的一些内容,希望能帮助您和/或其他人理解(begin ()).

我最常(begin ())像您在(if ())语句中那样使用,因为该函数在条件之后只有两个插槽。

因此,(begin ())当打算评估条件“在道路上分开”的一侧或两侧的多个语句时,它本身就变得有用。

一个例子:

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

上面我只(begin ())在我希望Chez执行两个单独的操作时使用,如果数字i是偶数。奇怪的时候i我不需要开始声明,我们可以继续。

请注意,Chez Scheme将按顺序评估 begin 语句的内容。在Scheme Programming Language中,它在页面底部附近说:

“语法形式 begin [...] 按从左到右的顺序计算其子表达式并返回最后一个子表达式的值,就像 let 或 lambda 表达式的主体一样。”

于 2017-06-29T22:06:13.187 回答