【问题标题】:Building the filter built-in function with Racket使用 Racket 构建过滤器内置功能
【发布时间】:2017-02-28 08:01:30
【问题描述】:

我正在尝试使用 Racket 构建过滤器(内置函数),只是作为一种实践。

我创建了以下代码:

(define (filter lista-1 check-function)
 (define (fil-iter lista-1 check-function lista-2)
  (cond ((null? lista-1) lista-2)
        ((check-function (car lista-1)) (fil-iter (cdr lista-1) check-function (append lista-2 (list (car lista-1)))))
        (else (fil-iter (cdr lista-1) check-function lista-2))))
   (trace fil-iter)
   (fil-iter lista-1 check-function '()))

我用“奇数?”、“偶数?”做了一些测试。和“号码?”作为“检查功能”。

所有输出都是正确的。但我可能什么都没看到……我的直觉说这里有问题。

【问题讨论】:

    标签: filter functional-programming lisp racket sicp


    【解决方案1】:

    可以使用for/list#:when 子句来创建过滤函数:

    (define (myfilter proc lst)
      (for/list ((item lst)
                 #:when (proc item))
        item))
    
    (myfilter even? '(1 2 3 4 5 6))
    ; => '(2 4 6)
    

    【讨论】:

      【解决方案2】:

      您的函数是正确的,只是它的复杂度为 n²,而它的复杂度可能为 n

      原因是您使用append 而不是cons 来构建结果,而append 的成本与列表的长度成正比,而cons 的成本是恒定的。因此,如果您想要一个具有线性复杂度的函数,您应该编写如下内容:

      (define (filter lista-1 check-function)
       (define (fil-iter lista-1 check-function lista-2)
        (cond ((null? lista-1) (reverse lista-2))
              ((check-function (car lista-1))
               (fil-iter (cdr lista-1) check-function (cons (car lista-1) lista-2)))
              (else (fil-iter (cdr lista-1) check-function lista-2))))
         (fil-iter lista-1 check-function '()))
      

      请注意,最后结果必须取反,但这不会改变函数的复杂度,因为reverse 具有与列表大小呈线性关系的复杂度,并且只在函数末尾执行一次.

      您还可以简化函数,注意参数check-function 在每次调用帮助程序fil-iter 时都不会修改,因此可以在其中省略:

      (define (filter lista-1 check-function)
       (define (fil-iter lista-1 lista-2)
        (cond ((null? lista-1) (reverse lista-2))
              ((check-function (car lista-1))
               (fil-iter (cdr lista-1) (cons (car lista-1) lista-2)))
              (else (fil-iter (cdr lista-1) lista-2))))
         (fil-iter lista-1 '()))
      

      【讨论】:

      • 你是我的教授!谢谢,另一个很好的解释!
      • 我在避免反向...有没有另一种方法可以使用 cons 而不是 append 而不是使用 reverse?
      • 那么您可以使用this answer 中显示的技术来解决您的问题之一。另一种方法是使用带有可变列表的副作用,但这在函数式编程中并不常见。我真的不明白你不想使用reverse 的方式:在尾递归函数中使用累加器时,reverse 的使用在 Scheme 和其他 lisp 语言中确实是惯用的。
      • 谢谢!我只是一个初学者。我不知道这是一种惯用行为。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-02-21
      • 2019-07-09
      • 1970-01-01
      • 2017-03-31
      • 1970-01-01
      相关资源
      最近更新 更多