仅使用“The Little Schemer”中的表单展平列表

时间:2011-09-05 23:29:25

标签: scheme the-little-schemer

我正在通过The LIttle Schemer来学习Scheme(作为一个老C程序员),作为一个练习我尝试编写一个程序来使用在The Little Schemer中的表单来展平列表;即,definelambdacondcarcdrandor等,但 append。我认为这很容易,但我无法提出解决方案。我怎么能这样做?

3 个答案:

答案 0 :(得分:10)

我有一个只使用“第一原则”操作的版本并且效率很高(与基于append的解决方案不同,不需要多次通过任何列表)。 : - )

它通过定义两个简单的构建块(foldreverse),然后在那些上面定义flatten(和它的帮助,reverse-flatten-into)来做到这一点(并注意每个函数如何只有一行或两行):

;; Similar to SRFI 1's fold
(define (fold1 kons knil lst)
  (if (null? lst)
      knil
      (fold1 kons (kons (car lst) knil) (cdr lst))))

;; Same as R5RS's reverse
(define (reverse lst)
  (fold1 cons '() lst))

;; Helper function
(define (reverse-flatten-into x lst)
  (if (pair? x)
      (fold1 reverse-flatten-into lst x)
      (cons x lst)))

(define (flatten . lst)
  (reverse (reverse-flatten-into lst '())))

使用的唯一外部函数是:conscarcdrnull?pair?

这个函数的关键见解是fold非常强大的操作,应该是任何Schemer工具包的一部分。而且,正如上面的代码所示,从第一原则构建它是如此简单!

答案 1 :(得分:2)

我不熟悉Little Schemer原语,所以你可能需要调整它以适应它。

我不确定这是否是您想要的答案,但您可以使用原语编写append

(define (append l1 l2)
  (cond
    ((null? l1) l2)
    (else (cons (car l1) (append (cdr l1) l2)))))

然后可以根据这个来编写flatten函数。

不确定这是否超出规则:)

答案 2 :(得分:2)

这是一次尝试。它可以避免使用缺点并避免追加,因为它只会消除它可以获得的第一个非对,并将其与它所构建的新尾部的扁平化相对应。有时它会重写列表,然后再次调用flatten。不是最有效的方式。

固定代码:

(define (flatten x)
  (cond 
    ((null? x) x)
    ((and (pair? x) 
          (not (pair? (car x))))
     (cond 
       ((null? (car x)) (flatten (cdr x)))
       (else (cons (car x) (flatten (cdr x))))))
    ((and (pair? x)
          (pair? (car x)))
     (flatten (cons (caar x) 
                    (cons (cdar x) (cdr x)))))
    (else (cons x '()))))