Scheme 方案(相当大)定义了一个;级别“;功能子

Scheme 方案(相当大)定义了一个;级别“;功能子,scheme,lambda,Scheme,Lambda,我试图在Scheme中定义一个函数,使用相当大的语言(在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) (co

我试图在Scheme中定义一个函数,使用相当大的语言(在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

有人能帮我解决这个错误吗?

在列表上追加工作。如果您使用列表调用
level
(1 2 3)第一次迭代它将执行
(append(level'1)(level(cdr'(2 3)))
。现在“1”不是一对,因此将计算为1,这是而不是列表。这将类似于调用
(append'1…
,这是违反合同的

编辑

这是一个相当大的
flatte
实现。它基于Chris Jester Young的。它比
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 '())))

Append对列表有效。如果您使用列表调用
level
(1 2 3)第一次迭代它将执行
(Append(level“1”)(level(cdr)(2 3))
。现在“1”不是一对,因此将计算为1,这是而不是列表。这就像调用
(APPEPEND“1…”
,这是违反合同的行为

编辑

这是一个相当大的
flatte
实现。它基于Chris Jester Young的。它比
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 '())))

Append对列表有效。如果您使用列表调用
level
(1 2 3)第一次迭代它将执行
(Append(level“1”)(level(cdr)(2 3))
。现在“1”不是一对,因此将计算为1,这是而不是列表。这就像调用
(APPEPEND“1…”
,这是违反合同的行为

编辑

这是一个相当大的
flatte
实现。它基于Chris Jester Young的。它比
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 '())))

Append对列表有效。如果您使用列表调用
level
(1 2 3)第一次迭代它将执行
(Append(level“1”)(level(cdr)(2 3))
。现在“1”不是一对,因此将计算为1,这是而不是列表。这就像调用
(APPEPEND“1…”
,这是违反合同的行为

编辑

这是一个相当大的
flatte
实现。它基于Chris Jester Young的。它比
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 '())))

有关如何实现展平的更多信息,请参阅

至于您的特定错误,
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)
将是一个列表,似乎您最终会使用非列表调用
级别
。您需要决定,例如,
(级别“a”)
是否应该合法,如果应该,应该是什么。目前,似乎您正试图使
(级别“a”)合法并返回
(a)
。这很好,但是你应该指定合同。如果这是你想要做的,那么你确实需要在你的
条件中使用第二个案例,但是由于
(a级)
应该返回
(a)
,你实际上需要该案例返回
(列表L)
,而不是
L

这里的另一个选项是,如果您确实希望
level
严格,并且总是需要一个列表作为参数,那么您需要添加更多的逻辑来确定
(car L)
是一个列表,如果是,则递归调用其上的
level
,然后调用
append
,并生成结果。一种方法如下:

(define (level L)
  (cond
    ((null? L) L)
    ((pair? L) (append (if (list? (car L))
                           (level (car L))
                           (list L))
                       (level (cdr L))))))

有关如何实现展平的更多信息,请参阅

至于您的特定错误,
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)
将是一个列表,似乎您最终会使用非列表调用
级别
。您需要决定,例如,
(级别“a”)
是否应该合法,如果应该,应该是什么。目前,似乎您正试图使
(级别“a”)合法并返回
(a)
。这很好,但您应该指定t