Scheme(Pretty Big)定义“级别”功能

时间:2013-10-14 17:44:07

标签: scheme lambda

我正在尝试在Scheme中定义一个函数,使用Pretty Big语言(在Dr. Racket中),它将获取一个列表并将所有'原子'转换为顶级元素。例如,如果给出:

(level '(a b (c d) (e f (g 4 h))))
;=> (a b c d e f g 4 h)

这是我到目前为止的代码:

;;level -takes list and returns list w/all elements as top-level
(define level
  (lambda (L)
    (cond ((null? L) L)
          ((not( pair? L)) L)
          (else (append (level(car L)) (level(cdr L)))))))

我的错误如下:

append: contract violation
  expected: list?
  given: d

任何人都可以帮我解决此错误吗?

3 个答案:

答案 0 :(得分:2)

有关如何实现flatten的更多信息(这通常称为此类函数),请查看

至于你的具体错误,append期望所有(通常可能需要两个以上)的参数成为列表。例如,

> (append '(1 2 3) '(4 5 6))
;=> (1 2 3 4 5 6)
> (append '(1 2 3) '(4 5 6) '(7 8 9))
;=> (1 2 3 4 5 6 7 8 9)

现在,你正在编写你的函数,并且你已经说level应该返回一个列表。这意味着如果level有几个不同的执行路径,则每个路径都需要生成一个列表。那么,让我们来看看你的实现。

(define level
  (lambda (L)
    (cond ((null? L) L)
          ((not( pair? L)) L)
          (else (append (level(car L)) (level(cdr L)))))))

在这个问题中,你说你正在写一个应该列出一个列表的函数,所以L可以是两件事之一;它可以是空列表,也可以是一对。目前,您的cond还有三个案例。

(cond ((null? L) L)                                  ; handle an empty list
      ((not( pair? L)) L)
      (else (append (level(car L)) (level(cdr L))))) ; handle a pair

如果您总是使用列表调用level,则不需要第二种情况。但是,由于在第三种情况下,您执行调用(level (car L)),并且您不知道(car L)是否会成为列表,您似乎 最终使用非列表调用level。您需要做出决定,例如(level 'a)是否合法,以及是否应该是合法的。目前,您似乎想让(level 'a)合法并返回(a)。那很好,但你应该指定合同。如果这是你想要做的,那么你需要cond中的第二种情况,但由于(level 'a)应该返回(a),你实际上需要这种情况才能返回(list L) },而不是L

这里的另一个选项,如果你希望level是严格的,并且总是需要一个列表作为参数,那么你需要添加一些逻辑来确定是否{ {1}}是一个列表,如果是,则以递归方式在其上调用(car L),并使用结果调用level。一种方法是这样的:

append

答案 1 :(得分:1)

在列表中附加作品。如果您使用列表level拨打'(1 2 3)第一次迭代,它将执行(append (level '1) (level (cdr '(2 3)))。现在' 1没有对,因此将评估为1,这是列表。这就像调用(append '1 ...)这是合同违规一样。

修改

以下是Pretty Big中flatten的实现。这是基于Chris Jester-Young的answer for a similar question。它比append版本效率更高。

(define (flatten lst)
  ;; helper function that accumulates
  (define (reverse-flatten-into x lst)
    (if (pair? x)
        (foldl reverse-flatten-into lst x)
        (cons x lst)))

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

答案 2 :(得分:0)

无论何时定义递归函数,每个子句都应该返回相似类型的对象。在您的情况下,第三个子句中的递归调用需要返回一个列表(供append使用),但第二个子句返回一个'atom'。因此编译器/运行时会抱怨'预期列表'。

对此的修复是在第二个(list L)子句中返回cond