【问题标题】:Scheme: advise on implementation of flatten方案:建议扁平化的实施
【发布时间】:2011-07-03 12:47:31
【问题描述】:

我对@9​​87654321@ 的实现如下所示:

(define flatten
  (lambda (lst)
    (if (null? lst)
        lst
        (append
          (rtn-lst (car lst))
          (flatten (cdr lst))))))

(define rtn-lst
  (lambda (lst)
    (cond 
      ((null? lst) 
        empty)
      ((atom? lst)
        (list lst))
      (else 
        (flatten lst)))))

虽然标准实现是:

(define (flatten lst)
  (cond 
    ((null? list)
      empty)
    ((list? (car lst))
      (append (flatten (car lst)) (flatten (cdr lst))))
    (else
      (cons (car lst) (flatten (cdr lst))))))

除了明显的冗长,我的代码还有什么问题?

【问题讨论】:

    标签: list functional-programming scheme flatten


    【解决方案1】:

    这样的事情怎么样:

    (define (flatten x y)
        (if (null? x)
            y
            (if (list? (car x))
                (flatten (append (car x) (cdr x)) y)
                (flatten (cdr x) (append y (list (car x)))))))
    (define (flat x)     
        (flatten x '()))
    
    > (flat '(1(2(3(4(5)6)7)8)9))
    (1 2 3 4 5 6 7 8 9)
    
    

    和闭包版本:

    (define (flatten x)  
            (define (flatten x y)
                (if (null? x)
                    y
                    (if (list? (car x))
                        (flatten (append (car x) (cdr x)) y)
                        (flatten (cdr x) (append y (list (car x)))))))
            (flatten x '()))
    
    > (flatten '(1(2(3(4(5)6)7)8)9))
    (1 2 3 4 5 6 7 8 9)
    

    【讨论】:

    • 重复地将单例列表附加到列表末尾((append y (list (car x)))) 必然具有二次时间行为。您的flatten 的列表重组让人想起经典gopher,应该是整体线性解决方案的基础。不要与递归作斗争;如果使代码 tail 递归导致它变成二次方,那么显然这是不希望的。
    【解决方案2】:

    这样的事情怎么样:

    (define foo
      (lambda (e)
        (cond ((pair? e) `(,@(foo (car e)) ,@(foo (cdr e))))
              ((null? e) '())
              (else (list e)))))
    

    例如:

    > (foo '(((2 3) (4 . 5) 8)))
    (2 3 4 5 8)
    

    这是你想要的吗?

    【讨论】:

      【解决方案3】:

      我会试试这个:

      (define rtn-lst
        (lambda (lst)
          (cond 
            ((list? lst)
              (if (null? lst)
                  empty
                  (flatten-list lst)))
            ((atom? lst)
              (list lst))
            (else 
              (flatten-list lst)))))
      

      可能我们有不同的 Scheme 实现。

      编辑:

      修改else分支:

      (define rtn-lst
        (lambda (lst)
          (cond 
            ((list? lst)
              (if (null? lst)
                  empty
                  (flatten-list lst)))
            (else 
              (list lst)))))
      

      【讨论】:

      • @Yasir 我的版本与 (list 1 2 3 4) 一起正常工作并返回 '(1 2 3 4) 所以你的推理缺少了一些东西。
      • R5RS:库程序:null? obj 如果 obj 是空列表,则返回 #t,否则返回 #f。因此,您可以使用每种数据类型调用 null?
      • @Yasir:这很有趣。您正在使用哪种方案实现?我正在使用将语言包设置为 "Essentials of Programming Languages (3rd ed.)" 的 DrRacket。抱歉太好奇了。我是 Scheme 和函数式编程的新手,因此我的目标是了解最佳实践和良好风格。
      • @sudhirc:我也在使用 Racket,但我的源代码中有 #lang racket,我使用的是 symbol? 而不是 atom?
      • @Yasir:谢谢,我可以看到将语言设置为球拍时的行为。但奇怪的是,当我设置#lang 球拍时,您的程序也无法返回任何内容。各种方案实现有那么大不同吗(读不兼容)?
      【解决方案4】:

      我认为atom? 是错误的。你想知道lst 是否是一个列表,所以使用list?。对于某些实现,atom? 可以在 vectorstring 上返回 false。但我不确定。其余的都很好。

      【讨论】:

      • 这看起来不错。除此之外,您如何看待整体风格?
      • 风格非常主观......但我会在rtn-lst 中为cond 使用更少的行,例如(cond ((null? lst) empty) ; nextline
      猜你喜欢
      • 2011-05-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多