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

时间:2016-04-17 23:53:27

标签: clojure scheme lisp

我正在尝试在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,由于(not (null? coll))函数中的条件partition-all,该列表永远不会发生。

我的功能出了什么问题?

1 个答案:

答案 0 :(得分:1)

根据我在评论中所说的内容,我非常确定{strong> cdr take给你提出问题。在ideone上以诡计运行你的代码给了我:

  

错误:在程序列表尾部:

     

错误:在过程list-tail中:位置1中的错误类型参数(期望对):()

因此,问题在于你试图获得一个不够长的列表尾部。只需采用最小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案例,否则结果列表不会以'()(空列表)结束,但会带有未指定的值。

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