【问题标题】:Scheme (Pretty Big) defining a "level" funciton定义“级别”函数的方案(相当大)
【发布时间】:2013-10-14 17:44:07
【问题描述】:

我正在尝试在 Scheme 中定义一个函数,使用 Pretty Big 语言(在 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

谁能帮我解决这个错误?

【问题讨论】:

    标签: scheme lambda


    【解决方案1】:

    更多关于如何实现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,则不需要第二种情况。但是,由于在第三种情况下,您 do 调用了(level (car L)),并且您不知道(car L) 是否会是一个列表,所以您似乎do em> 最终使用非列表调用level。您需要决定 (level 'a) 是否应该合法,如果应该,应该是什么。目前,您似乎正试图让(level 'a) 合法并返回(a)。没关系,但您应该指定合同。如果这是您想要做的,那么您确实需要cond 中的第二种情况,但由于(level 'a) 应该返回(a),您实际上需要这种情况来返回(list 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))))))
    

    【讨论】:

      【解决方案2】:

      Append 适用于列表。如果您使用列表'(1 2 3) 调用level,那么第一次迭代它将执行(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 '())))
      

      【讨论】:

        【解决方案3】:

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

        解决此问题的方法是在第二个 cond 子句中返回 (list L)

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-07-16
          • 1970-01-01
          • 2012-05-13
          • 2015-11-25
          相关资源
          最近更新 更多