为什么这个递归函数将空集合传递给“take”?

Why does this recursive function pass an empty collection to `take`?

我正在尝试在 Scheme 中编写 Clojure 的 partition-all 函数的实现:

(define (take lst n)
  (if (= n 0)
      '()
      (cons (car lst) (take (cdr lst) (- n 1)))))

(define (partition-all n step coll)
  (if (not (null? coll))
      (cons (take coll (min n (length coll)))
            (partition-all n step (list-tail coll step)))))

但是口译员对我大吼:

cdr: expected pair in argument #1

这意味着,在某些时候,一个空列表 '() 被传递给 take,由于 partition-all 中的条件 (not (null? coll)),这永远不会发生功能。

我的功能有什么问题?

根据我在评论中所说的内容,我非常确定 而不是 take 中的 cdr 给您带来了问题。 运行 你在 ideone 上的诡计代码给了我:

ERROR: In procedure list-tail:

ERROR: In procedure list-tail: Wrong type argument in position 1 (expecting pair): ()

因此,问题是您正在尝试获取不够长的列表尾部。这可以通过仅取 step 和集合长度中的最小值来缓解:

(define (take lst n)
  (if (= n 0)
      '()
      (cons (car lst) (take (cdr lst) (- n 1)))))

(define (partition-all n step coll)
  (if (not (null? coll))
      (cons (take coll (min n (length coll)))
            (partition-all n step (list-tail coll (min (length coll) step))))
                                                 ;;^^^^^^^^^^^^^^^^^
      '()
    ;;^^^
         ))


(display (partition-all 3 2 '(a b c d e f g)))
; => ((a b c) (c d e) (e f g) (g))

(Live on ideone)

请注意,我还在 if 中添加了一个 else 案例,否则结果列表不是以 '()(空列表)结束,而是以一个未指定的值结束。

另请注意,您的两个函数都不是尾递归的。